require_relative "../helpers/app"
require_relative "../helpers/github"
require_relative "../helpers/pretty_table"

module Fastlane
  module Actions
    class DistributeArtifactsAction < Action
      def self.run(params)
        channel = params[:channel]
        artifact_path = resolve_artifact_path(
          artifact_path: params[:artifact_path],
          channel: channel,
          workflow_path: params[:workflow_path],
          workflow_branch: params[:workflow_branch],
          download_dir: params[:download_dir]
        )
        build_info = other_action.analyze_artifacts(artifact_path: artifact_path)

        install_url = case channel
        when DistributionChannel::FIREBASE
          distribute_via_firebase(
            build_info: build_info,
            artifact_path: artifact_path,
            group: params[:firebase_group],
            testers: params[:firebase_testers]
          )
        when DistributionChannel::PLAYSTORE
          distribute_via_playstore(
            build_info: build_info,
            artifact_path: artifact_path,
            track: params[:playstore_track]
          )
        else
          UI.user_error!("Unknown distribution channel: #{channel}")
        end

        unless install_url.nil?
          UI.success("Successfully distributed the build to #{channel}: #{install_url}")
        end

        install_url
      end

      def self.resolve_artifact_path(artifact_path:, channel:, workflow_path:, workflow_branch:, download_dir:)
        if artifact_path
          unless File.exist?(artifact_path)
            UI.user_error!("Build artifact path does not exist: #{artifact_path}")
          end
          return artifact_path
        end

        other_action.download_artifacts(
          workflow_path: workflow_path,
          workflow_branch: workflow_branch,
          download_dir: download_dir,
          extension: (channel == DistributionChannel::PLAYSTORE) ? "aab" : "apk"
        )
      end

      def self.distribute_via_firebase(build_info:, artifact_path:, group:, testers:, max_commits: 100)
        UI.verbose("Generating release notes...")
        release_tag = nil

        release_notes = if build_info[:pr]
          pr = Github.get_pr(number: build_info[:pr])
          [
            "Custom build for PR: #{build_info[:pr]} #{pr[:title]} (#{pr[:url]})",
            "",
            pr[:body],
            "",
            Git.summarize_changes(sha: build_info[:sha], previous_sha: pr[:baseRefOid], max_commits: max_commits)
          ].join("\n")
        elsif build_info[:branch]
          base_sha = Github.branch_sha(branch: Git.default_branch)
          [
            "Custom build for branch #{build_info[:branch]} (#{Github.branch_link(build_info[:branch])})",
            "",
            Git.summarize_changes(sha: build_info[:sha], previous_sha: base_sha, max_commits: max_commits)
          ].join("\n")
        else
          release_tag = "#{build_info[:build_flavor]}/v#{build_info[:version_name]}"
          previous_release_tag = `git tag -l --sort=-creatordate '#{build_info[:build_flavor]}/v*' 2>/dev/null | head -n 1`.strip
          if release_tag == previous_release_tag
            UI.important("Skipping distribution as the version name matches the latest release!")
            return nil
          elsif previous_release_tag != ""
            previous_release_sha = `git rev-parse #{previous_release_tag}`.strip
            [
              "Main branch build for commit: #{build_info[:sha]} (#{Github.commit_link(build_info[:sha])})",
              "",
              Git.summarize_changes(sha: build_info[:sha], previous_sha: previous_release_sha, max_commits: max_commits)
            ].join("\n")
          else
            "Main branch build for commit: #{build_info[:sha]} (#{Github.commit_link(build_info[:sha])})"
          end
        end

        UI.important("Generated release notes:")
        release_notes.split("\n").each do |line|
          UI.message("  #{line.cyan}")
        end

        apk_path = "#{File.dirname(artifact_path)}/#{File.basename(artifact_path, File.extname(artifact_path))}.apk"
        other_action.extract_apk(artifact_path: artifact_path, apk_path: apk_path)
        firebase_app_id = App.get_firebase_id(build_info[:build_flavor])

        other_action.firebase_app_distribution(
          app: firebase_app_id,
          service_credentials_json_data: other_action.firebase_credentials,
          groups: group,
          testers: testers,
          debug: true,
          android_artifact_type: "APK",
          android_artifact_path: apk_path,
          release_notes: release_notes
        )

        release = lane_context[SharedValues::FIREBASE_APP_DISTRO_RELEASE]
        UI.verbose("Firebase release:\n#{JSON.pretty_generate(release)}")

        # force uppsert a tag that points at build
        if release_tag && build_info[:sha]
          Actions.sh("git tag -f #{release_tag} #{build_info[:sha]}", log: true)
          Actions.sh("git push --force origin #{release_tag}", log: true)
        end

        release[:testingUri]
      end

      def self.distribute_via_playstore(build_info:, artifact_path:, track:)
        unless build_info[:artifact_type] == "AAB"
          UI.user_error!("Only AAB artifacts are supported for PlayStore distribution")
        end
        unless build_info[:pr].nil?
          UI.user_error!("PlayStore distribution is not supported for pull requests. Please use Firebase distribution instead.")
        end

        other_action.upload_to_play_store(
          package_name: build_info[:package_name],
          version_code: build_info[:version_code],
          version_name: build_info[:version_name],
          track: track,
          release_status: "completed",
          aab: artifact_path,
          json_key_data: other_action.playstore_credentials
        )

        App.get_playstore_link(build_flavor: build_info[:build_flavor], track: track)
      end

      def self.ensure_json(key)
        JSON.parse(key)
        key
      rescue JSON::ParserError => e
        UI.verbose("Key is not JSON, attempting Base64 decode: #{e.message}")
        Base64.decode64(key)
      end

      def self.description
        "Distribute a build artifact to Firebase or Play Store"
      end

      def self.available_options
        [
          FastlaneCore::ConfigItem.new(key: :channel,
            description: "Distribution channel (#{DistributionChannel::ALL.join(", ")})",
            verify_block: proc do |value|
              unless value && DistributionChannel::ALL.include?(value.to_s.strip.downcase)
                UI.user_error!("Channel must be one of: #{DistributionChannel::ALL.join(", ")}")
              end
            end),
          FastlaneCore::ConfigItem.new(key: :artifact_path,
            description: "Path to the build artifact",
            optional: true,
            verify_block: proc do |value|
              UI.user_error!("Build artifact path must be valid") unless File.exist?(value)
            end),
          FastlaneCore::ConfigItem.new(key: :workflow_path,
            description: "Workflow used to locate artifacts when no path is provided",
            optional: true,
            verify_block: proc do |value|
              UI.user_error!("Workflow path must be a valid Github Actions workflow: #{value}") unless Github::Workflows.is_valid_path?(value)
            end),
          FastlaneCore::ConfigItem.new(key: :workflow_branch,
            description: "Branch to read workflow runs from",
            optional: true,
            verify_block: proc do |value|
              UI.user_error!("Workflow branch is required") if value.nil? || value.empty?
            end),
          FastlaneCore::ConfigItem.new(key: :download_dir,
            description: "Directory for downloaded artifacts",
            default_value: File.expand_path("build/artifacts"),
            verify_block: proc do |value|
              UI.user_error!("Download directory cannot be empty") if value.nil? || value.empty?
              expanded = File.expand_path(value)
              if File.exist?(expanded) && !File.directory?(expanded)
                UI.user_error!("Download directory must be a directory")
              end
              FileUtils.mkdir_p(expanded)
            end),
          FastlaneCore::ConfigItem.new(key: :firebase_group,
            description: "Firebase group to distribute to",
            optional: true,
            verify_block: proc do |value|
              UI.user_error!("Firebase group must be valid") if value && value.empty?
            end),
          FastlaneCore::ConfigItem.new(key: :firebase_testers,
            description: "Comma-separated emails of the firebase testers to distribute to",
            optional: true,
            verify_block: proc do |value|
              UI.user_error!("Firebase testers must be valid") if value && value.empty?
            end),
          FastlaneCore::ConfigItem.new(key: :playstore_track,
            description: "Play Store track (#{PlayStoreTrack::ALL.join(", ")})",
            default_value: PlayStoreTrack::DEFAULT,
            verify_block: proc do |value|
              if value && !PlayStoreTrack::ALL.include?(value)
                UI.user_error!("Invalid track (must be #{PlayStoreTrack::ALL.join(", ")})")
              end
            end)
        ]
      end

      def self.authors
        ["Suno"]
      end

      def self.is_supported?(platform)
        platform == :android
      end
    end
  end
end
