# Roomfit Studio (B2B) — Android Fastlane
#
# Mirrors apps/b2b/ios/fastlane/Fastfile. Manual `flutter build appbundle`
# runs have shipped builds without `--dart-define=SUPABASE_ANON_KEY`,
# producing a fail-fast crash screen that Google flagged on 2026-04-23 as
# "손상된 기능 정책 위반 / 로드 문제" (Play Store rejection of v1.0.0+1).
# Every lane below validates the environment before invoking Flutter, so a
# misconfigured AAB cannot reach Play Console.

default_platform(:android)

# ── Constants ────────────────────────────────────────────────────────
APP_IDENTIFIER = "com.roomfit.roomfit_studio"

APP_ROOT = File.expand_path("../..", __dir__)        # apps/b2b
ANDROID_ROOT = File.expand_path("..", __dir__)       # apps/b2b/android
PUBSPEC_PATH = File.expand_path("../../pubspec.yaml", __dir__)
DOTENV_PATH = File.expand_path("../../.env", __dir__)

KEY_PROPERTIES_PATH = File.expand_path("../key.properties", __dir__)
PLAY_JSON_KEY = File.expand_path("../secrets/play-console-service-account.json", __dir__)

AAB_PATH = File.expand_path("../../build/app/outputs/bundle/release/app-release.aab", __dir__)

# Dart-define keys that a production build MUST have. Missing any one
# of these aborts the lane before a single Flutter command runs.
REQUIRED_DART_DEFINES = %w[SUPABASE_ANON_KEY].freeze

# ── Helpers ──────────────────────────────────────────────────────────
def load_dotenv
  return unless File.exist?(DOTENV_PATH)
  File.foreach(DOTENV_PATH) do |line|
    next if line.strip.empty? || line.strip.start_with?("#")
    k, v = line.split("=", 2)
    ENV[k.strip] ||= v.to_s.strip.sub(/\A"(.*)"\z/, '\1')
  end
end

def assert_required_env!
  missing = REQUIRED_DART_DEFINES.select { |k| ENV[k].to_s.strip.empty? }
  return if missing.empty?
  UI.user_error!(
    "Missing required env vars: #{missing.join(", ")}. " \
    "Define them in `apps/b2b/.env` or export before running fastlane. " \
    "See apps/b2b/.env.example.",
  )
end

def read_pubspec_version
  raw = File.read(PUBSPEC_PATH, encoding: "UTF-8")
  match = raw.match(/^version:\s*(\d+\.\d+\.\d+)(?:\+(\d+))?/m)
  UI.user_error!("pubspec.yaml version 파싱 실패") unless match
  [match[1], match[2] || "0"]
end

def write_pubspec_version(version_name, build_number)
  raw = File.read(PUBSPEC_PATH, encoding: "UTF-8")
  updated = raw.sub(
    /^version:\s*\d+\.\d+\.\d+(?:\+\d+)?.*$/,
    "version: #{version_name}+#{build_number}",
  )
  File.write(PUBSPEC_PATH, updated, encoding: "UTF-8")
end

def bump_version(version_name, kind)
  parts = version_name.split(".").map(&:to_i)
  case kind.to_s.downcase
  when "patch"
    parts[2] += 1
  when "minor"
    parts[1] += 1
    parts[2] = 0
  when "major"
    parts[0] += 1
    parts[1] = 0
    parts[2] = 0
  else
    UI.user_error!("BUMP_VERSION 값이 잘못됨: #{kind}. patch/minor/major 중 선택.")
  end
  parts.join(".")
end

def parse_keystore_path
  return nil unless File.exist?(KEY_PROPERTIES_PATH)
  File.foreach(KEY_PROPERTIES_PATH) do |line|
    if (m = line.match(/^\s*storeFile\s*=\s*(.+?)\s*$/))
      raw = m[1].sub(/\A"(.*)"\z/, '\1')
      return File.expand_path(raw, ANDROID_ROOT)
    end
  end
  nil
end

def ensure_signing_assets(require_play_api: false)
  missing = []
  missing << "key.properties (#{KEY_PROPERTIES_PATH})" unless File.exist?(KEY_PROPERTIES_PATH)

  keystore = parse_keystore_path
  if keystore && !File.exist?(keystore)
    missing << "upload-keystore (#{keystore} — referenced by key.properties)"
  elsif keystore.nil? && File.exist?(KEY_PROPERTIES_PATH)
    missing << "storeFile entry inside key.properties"
  end

  if require_play_api && !File.exist?(PLAY_JSON_KEY)
    missing << "play-console-service-account.json (#{PLAY_JSON_KEY})"
  end

  return if missing.empty?

  UI.user_error!(
    "Android 배포 자산 누락: #{missing.join(', ')}.\n" \
    "- key.properties / upload-keystore.jks: ~/.android-keystores/roomfit-studio-upload.jks " \
    "또는 Wespion vault 에서 복사. SHA-1 46:3B:3D:C4:D1:6C:F3:7A:FF:6D:EF:5B:3A:F7:11:AC:13:FC:B9:CC.\n" \
    "- play-console-service-account.json: Wespion Play Console → Settings → API access\n" \
    "  에서 Service Account 생성 후 JSON 다운로드 → apps/b2b/android/secrets/ 에 저장\n" \
    "  (gitignored 확인). 서비스 계정에 'Release manager' 권한 부여 필수.",
  )
end

def dart_define_args
  REQUIRED_DART_DEFINES.map { |k| "--dart-define=#{k}=#{ENV[k]}" }.join(" ")
end

def resolve_version_and_build(require_play_api: false, fallback_build: 1)
  current_version, current_build = read_pubspec_version
  UI.message("Current pubspec.yaml: #{current_version}+#{current_build}")

  version_name =
    if !ENV["VERSION_NAME"].to_s.empty?
      ENV["VERSION_NAME"]
    elsif !ENV["BUMP_VERSION"].to_s.empty?
      bump_version(current_version, ENV["BUMP_VERSION"])
    else
      current_version
    end

  build_number =
    if !ENV["BUILD_NUMBER"].to_s.empty?
      ENV["BUILD_NUMBER"].to_i
    elsif require_play_api && File.exist?(PLAY_JSON_KEY)
      begin
        latest = google_play_track_version_codes(
          package_name: APP_IDENTIFIER,
          track: "internal",
          json_key: PLAY_JSON_KEY,
        )
        (Array(latest).map(&:to_i).max || 0) + 1
      rescue => e
        UI.important(
          "google_play_track_version_codes 실패 (#{e.class}: #{e.message}) — " \
          "build_number=#{fallback_build} fallback. 명시 override 는 BUILD_NUMBER=...",
        )
        fallback_build
      end
    else
      current_build.to_i + 1
    end

  [version_name, build_number, current_version, current_build]
end

def build_aab(version_name, build_number)
  sh(
    "cd #{APP_ROOT} && flutter build appbundle --release " \
    "--build-name=#{version_name} --build-number=#{build_number} " \
    "#{dart_define_args}",
  )
  UI.user_error!("AAB not found at #{AAB_PATH}") unless File.exist?(AAB_PATH)
  AAB_PATH
end

# ── Lanes ────────────────────────────────────────────────────────────
platform :android do
  before_all do
    load_dotenv
  end

  desc "Validate env + signing assets are ready for a release AAB"
  lane :preflight do
    assert_required_env!
    UI.success("✅ env OK (#{REQUIRED_DART_DEFINES.join(", ")} present)")

    ensure_signing_assets(require_play_api: false)
    UI.success("✅ signing assets OK (key.properties + upload-keystore present)")

    if File.exist?(PLAY_JSON_KEY)
      UI.success("✅ Play Console service account JSON present — `internal` lane available")
    else
      UI.important(
        "ℹ️  Play Console service account JSON 미발급 (#{PLAY_JSON_KEY}). " \
        "지금은 `aab` lane 으로 AAB 만들어 수동 업로드 가능. " \
        "자동화하려면 위 ensure_signing_assets 안내대로 발급.",
      )
    end
  end

  desc "Build a signed release AAB (no upload). Output: build/app/outputs/bundle/release/app-release.aab"
  lane :aab do
    assert_required_env!
    ensure_signing_assets(require_play_api: false)

    version_name, build_number, prev_v, prev_b = resolve_version_and_build(
      require_play_api: false,
      fallback_build: 1,
    )

    UI.important("📦 Building AAB #{version_name}+#{build_number} (prev: #{prev_v}+#{prev_b})")
    write_pubspec_version(version_name, build_number)

    out = build_aab(version_name, build_number)
    UI.success("✅ AAB built at #{out}")
    UI.message("Upload manually at https://play.google.com/console → Roomfit Studio → 내부 테스트 → 새 출시 만들기")
  end

  desc "Build signed AAB and upload to Play Console Internal Testing"
  lane :internal do
    assert_required_env!
    ensure_signing_assets(require_play_api: true)

    version_name, build_number, prev_v, prev_b = resolve_version_and_build(
      require_play_api: true,
      fallback_build: 2,
    )

    UI.important("🤖 Deploying #{version_name}+#{build_number} → internal (prev: #{prev_v}+#{prev_b})")
    write_pubspec_version(version_name, build_number)

    aab = build_aab(version_name, build_number)

    release_status = ENV["RELEASE_STATUS"].to_s.empty? ? "draft" : ENV["RELEASE_STATUS"]

    upload_to_play_store(
      package_name: APP_IDENTIFIER,
      track: "internal",
      aab: aab,
      release_status: release_status,
      json_key: PLAY_JSON_KEY,
      skip_upload_metadata: true,
      skip_upload_changelogs: true,
      skip_upload_images: true,
      skip_upload_screenshots: true,
    )

    UI.success("✅ Uploaded #{version_name}+#{build_number} to Play Console Internal Testing (#{release_status})")
    UI.message("pubspec.yaml 은 새 버전으로 업데이트됨. git commit 여부는 수동 판단.")
  end

  desc "Promote latest internal release to production. ROLLOUT=0.05 for 5% staged rollout (default), or RELEASE_STATUS=draft for manual publish."
  lane :promote_to_production do
    ensure_signing_assets(require_play_api: true)

    # Default: staged 5% rollout (inProgress). Override with RELEASE_STATUS=draft
    # for manual publish via Play Console UI, or RELEASE_STATUS=completed for
    # immediate 100% rollout (NOT recommended for first promote).
    release_status = ENV["RELEASE_STATUS"].to_s.empty? ? "inProgress" : ENV["RELEASE_STATUS"]
    rollout = ENV["ROLLOUT"].to_s.empty? ? "0.05" : ENV["ROLLOUT"]

    args = {
      package_name: APP_IDENTIFIER,
      track: "internal",
      track_promote_to: "production",
      track_promote_release_status: release_status,
      json_key: PLAY_JSON_KEY,
      skip_upload_apk: true,
      skip_upload_aab: true,
      skip_upload_metadata: true,
      skip_upload_changelogs: true,
      skip_upload_images: true,
      skip_upload_screenshots: true,
    }
    args[:rollout] = rollout if release_status == "inProgress"

    UI.important("🚀 Promoting internal → production (status=#{release_status}#{release_status == 'inProgress' ? ", rollout=#{rollout}" : ''})")
    upload_to_play_store(**args)
    UI.success("✅ Promoted to production (#{release_status}#{release_status == 'inProgress' ? " · #{(rollout.to_f * 100).round}% rollout" : ''})")
  end
end
