require_relative "../helpers/config"
require_relative "../helpers/git"
require_relative "../helpers/github"
require "yaml"
require "json"
require "base64"

module Fastlane
  module DistributionChannel
    TESTFLIGHT = "testflight"
    FIREBASE = "firebase"
    ALL = [TESTFLIGHT, FIREBASE]
  end

  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)

        PrettyTable.print(data: build_info, title: "Build Info")

        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::TESTFLIGHT
          distribute_via_testflight(
            build_info: build_info,
            artifact_path: artifact_path,
          )
        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: "ipa"
        )
      end

      def self.distribute_via_firebase(build_info:, artifact_path:, group:, testers:, max_commits: 100)
        build_config = BuildConfig.for(build_info[:build_flavor])
        firebase_credentials = other_action.firebase_credentials

        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

        other_action.firebase_app_distribution(
          googleservice_info_plist_path: build_config[:google_services_plist],
          service_credentials_json_data: firebase_credentials,
          groups: group,
          testers: testers,
          debug: true,
          ipa_path: artifact_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_testflight(build_info:, artifact_path:)
        unless build_info[:pr].nil?
          UI.user_error!("TestFlight distribution is not supported for pull requests. Please use Firebase distribution instead.")
        end

        other_action.upload_to_testflight(
          api_key: other_action.testflight_credentials,
          skip_waiting_for_build_processing: true,
          localized_build_info: {
            default: {
              whats_new: "Bug fixes and performance improvements"
            },
            "en-US": {
              whats_new: "Bug fixes and performance improvements"
            },
            "fr-FR": {
              whats_new: "Corrections de bugs et améliorations des performances"
            },
            "de-DE": {
              whats_new: "Fehlerbehebungen und Leistungsverbesserungen"
            },
            "it-IT": {
              whats_new: "Correzioni di bug e miglioramenti delle prestazioni"
            },
            "ja-JP": {
              whats_new: "バグ修正およびパフォーマンス改善"
            },
            "ko-KR": {
              whats_new: "버그 수정 및 성능 개선"
            },
            "pl-PL": {
              whats_new: "Poprawki błędów i ulepszenia wydajności"
            },
            "pt-BR": {
              whats_new: "Correções de erros e melhorias de desempenho"
            },
            "pt-PT": {
              whats_new: "Correções de erros e melhorias de desempenho"
            },
            "ru-RU": {
              whats_new: "Исправлены ошибки и улучшена производительность"
            },
            "es-MX": {
              whats_new: "Corrección de errores y mejoras de rendimiento"
            },
            "es-ES": {
              whats_new: "Corrección de errores y mejoras de rendimiento"
            },
            "tr-TR": {
              whats_new: "Hata düzeltmeleri ve performans iyileştirmeleri"
            }
          },
          app_identifier: build_info[:app_identifier],
          ipa: artifact_path,
        )
      end

      def self.description
        "Distribute the build artifact to the selected channel"
      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 ipa file",
            type: String,
            optional: true,
            verify_block: proc do |value|
              UI.user_error!("Artifact path must be valid") unless File.exist?(value)
              UI.user_error!("Artifact path must be an ipa file") unless File.extname(value) == ".ipa"
            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),
        ]
      end

      def self.authors
        ["Suno"]
      end

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

    end
  end
end
