project_dir = File.expand_path('..', Dir.pwd)

require_relative File.join(project_dir, 'fastlane-config', 'android_config')
require_relative File.join(project_dir, 'fastlane-config', 'ios_config')
require_relative './config/config_helpers'

default_platform(:android)

platform :android do
  desc "Assemble debug APKs."
  lane :assembleDebugApks do |options|
    gradle(
      tasks: ["assembleDebug"],
    )
  end

  desc "Assemble Release APK"
  lane :assembleReleaseApks do |options|
    signing_config = FastlaneConfig.get_android_signing_config(options)

    # Generate version
    generateVersion = generateVersion()

    buildAndSignApp(
      taskName: "assemble",
      buildType: "Release",
      **signing_config
    )
  end

  desc "Bundle Release APK"
  lane :bundleReleaseApks do |options|
    signing_config = FastlaneConfig.get_android_signing_config(options)

    # Generate version
    generateVersion = generateVersion()

    buildAndSignApp(
      taskName: "bundle",
      buildType: "Release",
      **signing_config
    )
  end

  desc "Publish Release Artifacts to Firebase App Distribution"
  lane :deployReleaseApkOnFirebase do |options|
    signing_config = FastlaneConfig.get_android_signing_config(options)
    firebase_config = FastlaneConfig.get_firebase_config(:android, :prod)
    build_paths = FastlaneConfig::AndroidConfig::BUILD_PATHS

    # Generate version
    generateVersion = generateVersion(
        platform: "firebase",
        **firebase_config
    )

    # Generate Release Note
    releaseNotes = generateReleaseNote()

    buildAndSignApp(
      taskName: "assembleProd",
      buildType: "Release",
      **signing_config
    )

    firebase_app_distribution(
      app: firebase_config[:appId],
      android_artifact_type: "APK",
      android_artifact_path: build_paths[:prod_apk_path],
      service_credentials_file: firebase_config[:serviceCredsFile],
      groups: firebase_config[:groups],
      release_notes: releaseNotes
    )
  end

  desc "Publish Demo Artifacts to Firebase App Distribution"
  lane :deployDemoApkOnFirebase do |options|
    signing_config = FastlaneConfig.get_android_signing_config(options)
    firebase_config = FastlaneConfig.get_firebase_config(:android, :demo)
    build_paths = FastlaneConfig::AndroidConfig::BUILD_PATHS

    # Generate version
    generateVersion = generateVersion(
      platform: "firebase",
      **firebase_config
    )

    # Generate Release Note
    releaseNotes = generateReleaseNote()

    buildAndSignApp(
      taskName: "assembleDemo",
      buildType: "Release",
      **signing_config
    )

    firebase_app_distribution(
      app: firebase_config[:appId],
      android_artifact_type: "APK",
      android_artifact_path: build_paths[:demo_apk_path],
      service_credentials_file: firebase_config[:serviceCredsFile],
      groups: firebase_config[:groups],
      release_notes: releaseNotes
    )
  end

  desc "Deploy internal tracks to Google Play"
  lane :deployInternal do |options|
    signing_config = FastlaneConfig.get_android_signing_config(options)
    build_paths = FastlaneConfig::AndroidConfig::BUILD_PATHS

    # Generate version
    generateVersion = generateVersion(platform: "playstore")

    # Generate Release Note
    releaseNotes = generateReleaseNote()

    # Write the generated release notes to default.txt
    buildConfigPath = "metadata/android/en-GB/changelogs/default.txt"
    FileUtils.mkdir_p(File.dirname(buildConfigPath))
    File.write(buildConfigPath, releaseNotes)

    buildAndSignApp(
      taskName: "bundleProd",
      buildType: "Release",
      **signing_config
    )

    upload_to_play_store(
      track: 'internal',
      aab: build_paths[:prod_aab_path],
      skip_upload_metadata: true,
      skip_upload_images: true,
      skip_upload_screenshots: true,
    )
  end

  desc "Promote internal tracks to beta on Google Play"
  lane :promoteToBeta do
    upload_to_play_store(
      track: 'internal',
      track_promote_to: 'beta',
      skip_upload_changelogs: true,
      skip_upload_metadata: true,
      skip_upload_images: true,
      skip_upload_screenshots: true,
    )
  end

  desc "Promote beta tracks to production on Google Play"
  lane :promote_to_production do
    upload_to_play_store(
      track: 'beta',
      track_promote_to: 'production',
      skip_upload_changelogs: true,
      skip_upload_metadata: true,
      skip_upload_images: true,
      skip_upload_screenshots: true,
    )
  end

  desc "Generate artifacts for the given [build] signed with the provided [keystore] and credentials."
  private_lane :buildAndSignApp do |options|
    # Get the project root directory
    project_dir = File.expand_path('..', Dir.pwd)

    # Construct the absolute path to the keystore
    keystore_path = File.join(project_dir, 'keystores', options[:storeFile])

    # Check if keystore exists
    unless File.exist?(keystore_path)
      UI.error "Keystore file not found at: #{keystore_path}"
      UI.error "Please ensure the keystore file exists at the correct location"
      exit 1  # Exit with error code 1
    end

    gradle(
      task: options[:taskName],
      build_type: options[:buildType],
      properties: {
        "android.injected.signing.store.file" => keystore_path,
        "android.injected.signing.store.password" => options[:storePassword],
        "android.injected.signing.key.alias" => options[:keyAlias],
        "android.injected.signing.key.password" => options[:keyPassword],
      },
      print_command: false,
    )
  end

  desc "Generate Version for different platforms"
  lane :generateVersion do |options|
    platform = (options[:platform] || 'git').downcase

    # Generate version file for all platforms
    gradle(tasks: ["versionFile"])

    # Set version from file with fallback
    version = File.read("../version.txt").strip rescue "1.0.0"
    ENV['VERSION'] = version

    case platform
    when 'playstore'
      prod_codes = google_play_track_version_codes(track: 'production')
      beta_codes = google_play_track_version_codes(track: 'beta')
      latest_code = (prod_codes + beta_codes).max || 1
      ENV['VERSION_CODE'] = (latest_code + 1).to_s

    when 'firebase'
      begin
        latest_release = firebase_app_distribution_get_latest_release(
          app: options[:appId],
          service_credentials_file: options[:serviceCredsFile]
        )
        latest_build_version = latest_release ? latest_release[:buildVersion].to_i : 0
        ENV['VERSION_CODE'] = (latest_build_version + 1).to_s
      rescue => e
        UI.error("Error generating Firebase version: #{e.message}")
        raise e
      end

    when 'git'
      # Calculate version code from git history
      commit_count = `git rev-list --count HEAD`.to_i
      ENV['VERSION_CODE'] = (commit_count << 1).to_s
    else
      UI.user_error!("Unsupported platform: #{platform}. Supported platforms are: playstore, firebase, git")
    end

    # Output the results
    UI.success("Generated version for #{platform}")
    UI.success("Set VERSION=#{ENV['VERSION']} VERSION_CODE=#{ENV['VERSION_CODE']}")
    version
  end

  desc "Generate release notes"
  lane :generateReleaseNote do |options|
    releaseNotes = changelog_from_git_commits(
      commits_count: 1,
    )
    releaseNotes
  end

  desc "Generate full release notes from specified tag or latest release tag"
  lane :generateFullReleaseNote do |options|
    def get_latest_tag
      latest = `git describe --tags --abbrev=0`.strip
      return latest unless latest.empty?

      latest = `git tag --sort=-creatordate`.split("\n").first
      return latest unless latest.nil? || latest.empty?

      nil
    end

    from_tag = options[:fromTag] || get_latest_tag
    UI.message "Using tag: #{from_tag || 'No tags found. Getting all commits...'}"

    commits = if from_tag && !from_tag.empty?
      `git log #{from_tag}..HEAD --pretty=format:"%B"`.split("\n")
    else
      `git log --pretty=format:"%B"`.split("\n")
    end

    categories = process_commits(commits)
    format_release_notes(categories)
  end

  private_lane :process_commits do |commits|
    notes = {
      "breaking" => [], "feat" => [], "fix" => [],
      "perf" => [], "refactor" => [], "style" => [],
      "docs" => [], "test" => [], "build" => [],
      "ci" => [], "chore" => [], "other" => []
    }

    commits.each do |commit|
      next if commit.empty? || commit.start_with?("Co-authored-by:", "Merge")

      if commit.include?("BREAKING CHANGE:") || commit.include?("!")
        notes["breaking"] << commit.sub(/^[^:]+:\s*/, "")
      elsif commit =~ /^(feat|fix|perf|refactor|style|docs|test|build|ci|chore)(\(.+?\))?:/
        notes[$1] << commit.sub(/^[^:]+:\s*/, "")
      else
        notes["other"] << commit
      end
    end
    notes
  end

  private_lane :format_release_notes do |categories|
    sections = {
      "breaking" => "💥 Breaking Changes",
      "feat" => "🚀 New Features",
      "fix" => "🐛 Bug Fixes",
      "perf" => "⚡ Performance Improvements",
      "refactor" => "♻️ Refactoring",
      "style" => "💅 Style Changes",
      "docs" => "📚 Documentation",
      "test" => "🧪 Tests",
      "build" => "📦 Build System",
      "ci" => "👷 CI Changes",
      "chore" => "🔧 Maintenance",
      "other" => "📝 Other Changes"
    }

    notes = ["# Release Notes", "\nRelease date: #{Time.now.strftime('%d-%m-%Y')}"]

    sections.each do |type, title|
      next if categories[type].empty?
      notes << "\n## #{title}"
      categories[type].each { |commit| notes << "\n- #{commit}" }
    end

    UI.message "Generated Release Notes:"
    UI.message notes.join("\n")
    notes.join("\n")
  end

end

platform :ios do

  #############################
  # Shared Private Lane Helpers
  #############################

  private_lane :setup_ci_if_needed do
      unless ENV['CI']
          UI.message("🖥️ Running locally, skipping CI-specific setup.")
      else
          setup_ci
      end
  end

  private_lane :load_api_key do |options|
      ios_config = FastlaneConfig::IosConfig::BUILD_CONFIG

      app_store_connect_api_key(
        key_id: options[:appstore_key_id] || ios_config[:key_id],
        issuer_id: options[:appstore_issuer_id] || ios_config[:issuer_id],
        key_filepath: options[:key_filepath] || ios_config[:key_filepath],
        duration: 1200
      )
  end

  private_lane :fetch_certificates_with_match do |options|
      ios_config = FastlaneConfig::IosConfig::BUILD_CONFIG
      match(
        type: options[:match_type] || ios_config[:match_type],
        app_identifier: options[:app_identifier] || ios_config[:app_identifier],
        readonly: true,
        git_url: options[:git_url] || ios_config[:git_url],
        git_branch: options[:git_branch] || ios_config[:git_branch],
        git_private_key: options[:git_private_key] || ios_config[:match_git_private_key],
        force_for_new_devices: true,
        api_key: Actions.lane_context[SharedValues::APP_STORE_CONNECT_API_KEY]
      )
  end

  private_lane :build_ios_project do |options|
      ios_config = FastlaneConfig::IosConfig::BUILD_CONFIG
      app_identifier = options[:app_identifier] || ios_config[:app_identifier]
      provisioning_profile_name = options[:provisioning_profile_name] || ios_config[:provisioning_profile_name]

      cocoapods(
        podfile: ios_config[:podfile_path],
        clean_install: true,
        repo_update: true
      )

      # Manual signing for your main app target
      update_code_signing_settings(
        use_automatic_signing: false,
        path: ios_config[:project_path],
        targets: [ios_config[:target]],
        team_id: ios_config[:team_id],
        code_sign_identity: ios_config[:code_sign_identity],
        profile_name: provisioning_profile_name,
        bundle_identifier: app_identifier
      )

      build_ios_app(
        scheme: ios_config[:scheme],
        workspace: ios_config[:workspace_path],
        output_name: ios_config[:output_name],
        output_directory: ios_config[:output_directory],
        configuration: ios_config[:configuration]
      )
  end

  private_lane :set_plist_values do
      ios_config = FastlaneConfig::IosConfig::BUILD_CONFIG
      update_plist(
        plist_path: ios_config[:plist_path],
        block: proc do |plist|
          plist["NSCameraUsageDescription"] = "We use the camera to scan QR codes to send and receive payments."
        end
      )
  end

  ###################
  # Main Public lanes
  ###################

  desc "Build Ios application"
  lane :build_ios do |options|
      ios_config = FastlaneConfig::IosConfig::BUILD_CONFIG

      cocoapods(
        podfile: ios_config[:podfile_path],
        clean_install: true,
        repo_update: true
      )

      build_ios_app(
          scheme: ios_config[:scheme],
          workspace: ios_config[:workspace_path],
          output_name: ios_config[:output_name],
          output_directory: ios_config[:output_directory],
          skip_codesigning: true,
          skip_archive: true
      )
  end

  desc "Build Signed Ios application"
  lane :build_signed_ios do |options|
      setup_ci_if_needed
      load_api_key(options)
      fetch_certificates_with_match(options)
      build_ios_project(options)
  end

  desc "Increment build number from latest Firebase release"
  lane :increment_version do |options|
    firebase_config = FastlaneConfig.get_firebase_config(:ios)
    ios_config = FastlaneConfig::IosConfig::BUILD_CONFIG

    latest_release = firebase_app_distribution_get_latest_release(
      app: firebase_config[:appId],
      service_credentials_file: options[:serviceCredsFile] || firebase_config[:serviceCredsFile]
    )

    if latest_release
      increment_build_number(
        xcodeproj: ios_config[:project_path],
        build_number: latest_release[:buildVersion].to_i + 1
      )
    else
      UI.important("⚠️ No existing Firebase release found. Skipping build number increment.")
    end
  end

  desc "Generate release notes"
  lane :generateReleaseNote do
    branchName = `git rev-parse --abbrev-ref HEAD`.chomp()
    releaseNotes = changelog_from_git_commits(
      commits_count: 1,
    )
    releaseNotes
  end

  desc "Upload iOS application to Firebase App Distribution"
  lane :deploy_on_firebase do |options|
    firebase_config = FastlaneConfig.get_firebase_config(:ios)

    increment_version(serviceCredsFile: firebase_config[:serviceCredsFile])

    build_signed_ios(
        options.merge(
            match_type: "adhoc",
            provisioning_profile_name: "match AdHoc org.mifospay"
        )
    )

    releaseNotes = generateReleaseNote()

    firebase_app_distribution(
      app: options[:firebase_app_id] || firebase_config[:appId],
      service_credentials_file: options[:serviceCredsFile] || firebase_config[:serviceCredsFile],
      release_notes: releaseNotes,
      groups: options[:groups] || firebase_config[:groups]
    )
  end

  desc "Upload beta build to TestFlight"
  lane :beta do |options|

      ios_config = FastlaneConfig::IosConfig::BUILD_CONFIG

      setup_ci_if_needed
      load_api_key(options)
      fetch_certificates_with_match(
        options.merge(match_type: "appstore")
      )

      increment_version_number(
        xcodeproj: ios_config[:project_path],
        version_number: ios_config[:version_number]
      )

      latest_build_number = latest_testflight_build_number(
        app_identifier: options[:app_identifier] || ios_config[:app_identifier],
        api_key: Actions.lane_context[SharedValues::APP_STORE_CONNECT_API_KEY],
        version: ios_config[:version_number]
      )

      increment_build_number(
        xcodeproj: ios_config[:project_path],
        build_number: latest_build_number + 1
      )

      set_plist_values

      build_ios_project(
        options.merge(
            provisioning_profile_name: "match AppStore org.mifospay"
        )
      )

      pilot(
        api_key: Actions.lane_context[SharedValues::APP_STORE_CONNECT_API_KEY],
        skip_waiting_for_build_processing: true
      )
  end

  desc "Upload iOS Application to AppStore"
  lane :release do |options|

     ios_config = FastlaneConfig::IosConfig::BUILD_CONFIG

      setup_ci_if_needed
      load_api_key(options)
      fetch_certificates_with_match(
        options.merge(match_type: "appstore")
      )

      increment_version_number(
        xcodeproj: ios_config[:project_path],
        version_number: ios_config[:version_number]
      )

      latest_build_number = latest_testflight_build_number(
        app_identifier: options[:app_identifier] || ios_config[:app_identifier],
        api_key: Actions.lane_context[SharedValues::APP_STORE_CONNECT_API_KEY],
        version: ios_config[:version_number]
      )

      increment_build_number(
        xcodeproj: ios_config[:project_path],
        build_number: latest_build_number + 1
      )

      set_plist_values

      build_ios_project(
        options.merge(
            provisioning_profile_name: "match AppStore org.mifospay"
        )
      )

      deliver(
        screenshots_path: ios_config[:screenshots_ios_path],
        metadata_path: options[:metadata_path] || ios_config[:metadata_path],
        submit_for_review: false, # Set to true if you want to auto-submit for review
        automatic_release: true, # Set to true if you want to auto-release once it approved
        api_key: Actions.lane_context[SharedValues::APP_STORE_CONNECT_API_KEY],
        skip_app_version_update: false,
        force: true, # Skips HTML report verification
        precheck_include_in_app_purchases: false,
        overwrite_screenshots: true,
        reject_if_possible: true,
        app_rating_config_path: ios_config[:app_rating_config_path],
        submission_information: {
          add_id_info_uses_idfa: false,
          add_id_info_limits_tracking: false,
          add_id_info_serves_ads: false,
          add_id_info_tracks_action: false,
          add_id_info_tracks_install: false,
          content_rights_has_rights: true,
          content_rights_contains_third_party_content: false,
          export_compliance_platform: 'ios',
          export_compliance_compliance_required: false,
          export_compliance_encryption_updated: false,
          export_compliance_app_type: nil,
          export_compliance_uses_encryption: false,
          export_compliance_is_exempt: true,
          export_compliance_contains_third_party_cryptography: false,
          export_compliance_contains_proprietary_cryptography: false,
          export_compliance_available_on_french_store: true
        }
      )
  end
end

platform :mac do
  #############################
  # Shared Private Lane Helpers
  #############################

  private_lane :setup_ci_if_needed do
    if ENV['CI']
      setup_ci
    else
      UI.message("🖥️ Running locally, skipping CI-specific setup.")
    end
  end

  private_lane :load_api_key_macos do |options|
    ios_config = FastlaneConfig::IosConfig::BUILD_CONFIG

    app_store_connect_api_key(
      key_id: options[:appstore_key_id] || ios_config[:key_id],
      issuer_id: options[:appstore_issuer_id] || ios_config[:issuer_id],
      key_filepath: options[:key_filepath] || ios_config[:key_filepath],
      duration: 1200
    )
  end

  private_lane :next_macos_build_number do |options|
    ios_config = FastlaneConfig::IosConfig::BUILD_CONFIG

      latest = latest_testflight_build_number(
        app_identifier: options[:app_identifier] || ios_config[:app_identifier],
        api_key: Actions.lane_context[SharedValues::APP_STORE_CONNECT_API_KEY],
        platform: "osx",
        version: ios_config[:version_number]
      )
      (latest.to_i + 1).to_s
  end

  # Resolve the most-recent generated .pkg path
    private_lane :find_pkg_path do
      project_dir = File.expand_path('..', Dir.pwd)
      Dir[File.join(project_dir, 'cmp-desktop', 'build', 'release', '**', 'pkg', '*.pkg')]
        .max_by { |p| File.mtime(p) } || UI.user_error!('PKG not found!')
    end

  ###################
  # Public lanes
  ###################

  desc "Build & upload macOS (.pkg) to TestFlight"
  lane :desktop_testflight do |options|
    setup_ci_if_needed
    load_api_key_macos(options)

    new_build_number = next_macos_build_number(options)

    gradle(
      tasks: ["packageReleasePkg"],
      properties: {
        "buildNumber" => new_build_number,
        "macOsAppStoreRelease" => true
      }
    )

    pkg_path = find_pkg_path
        UI.message("Found PKG at: #{pkg_path}")

    pilot(
      api_key: Actions.lane_context[SharedValues::APP_STORE_CONNECT_API_KEY],
      pkg: pkg_path,
      app_platform: 'osx',
      skip_waiting_for_build_processing: true,
    )
  end

  desc "Build & submit macOS app to App Store (non-beta)"
    lane :desktop_release do |options|
     ios_config = FastlaneConfig::IosConfig::BUILD_CONFIG
      setup_ci_if_needed
      load_api_key_macos(options)

      new_build_number = next_macos_build_number(options)

      gradle(
        tasks: ["packageReleasePkg"],
        properties: {
          "buildNumber" => new_build_number,
          "macOsAppStoreRelease" => true
        }
      )

      # Locate the produced PKG (adjust pattern if you rename)
      pkg_path = find_pkg_path
          UI.message("Found PKG at: #{pkg_path}")

      deliver(
        platform: 'osx',
        pkg: pkg_path,
        screenshots_path: ios_config[:screenshots_macos_path],
        metadata_path: options[:metadata_path] || ios_config[:metadata_path],
        submit_for_review: true, # Set to true if you want to auto-submit for review
        automatic_release: true, # Set to true if you want to auto-release once it approved
        api_key: Actions.lane_context[SharedValues::APP_STORE_CONNECT_API_KEY],
        skip_app_version_update: false,
        force: true, # Skips HTML report verification
        precheck_include_in_app_purchases: false,
        overwrite_screenshots: true,
        reject_if_possible: true,
        app_rating_config_path: ios_config[:app_rating_config_path],
        submission_information: {
          add_id_info_uses_idfa: false,
          add_id_info_limits_tracking: false,
          add_id_info_serves_ads: false,
          add_id_info_tracks_action: false,
          add_id_info_tracks_install: false,
          content_rights_has_rights: true,
          content_rights_contains_third_party_content: false,
          export_compliance_platform: 'osx',
          export_compliance_compliance_required: false,
          export_compliance_encryption_updated: false,
          export_compliance_app_type: nil,
          export_compliance_uses_encryption: false,
          export_compliance_is_exempt: true,
          export_compliance_contains_third_party_cryptography: false,
          export_compliance_contains_proprietary_cryptography: false,
          export_compliance_available_on_french_store: true
        }
      )
  end
end