import SwiftUI
import NucleicProtocol

/// How this copy of the remote was built — the iOS mirror of the Mac's `BuildChannel`.
/// Stamped at archive time via the `NucleicChannel` Info.plist key (`$(NUCLEIC_CHANNEL)`,
/// see scripts/ios-release.sh); unset builds fall back to runtime detection (Debug → local,
/// TestFlight → beta, App Store → release).
enum BuildChannel {
    /// The `dev` channel — red "Local Development Build" banner.
    case local
    /// The `canary` channel — canary-yellow "Canary" banner with the bird. The bleeding-edge
    /// distributed channel, cut before beta (see BUILD.md).
    case canary
    /// The `beta` channel — blue "Beta" banner.
    case beta
    /// The `rc` channel — gold "Release Candidate" banner.
    case releaseCandidate
    /// The `stable` channel — no banner.
    case release

    /// The wire projection sent to the host in `hello`, so it can gate the connection on
    /// channel compatibility (`ReleaseChannel.isCompatible`).
    var releaseChannel: ReleaseChannel {
        switch self {
        case .local: .local
        case .canary: .canary
        case .beta: .beta
        case .releaseCandidate: .releaseCandidate
        case .release: .release
        }
    }
}

/// Build identity for the running app: which channel it came from and its build label.
/// Both platforms show the short git commit: the Mac embeds it via a prebuild plugin, and
/// here the NucleicRemote target's "Stamp git commit into Info.plist" build phase writes
/// `git rev-parse --short HEAD` into the `NucleicCommit` Info.plist key. Falls back to
/// `CFBundleVersion` (the `git rev-list --count` build number from scripts/ios-release.sh)
/// when git isn't available.
struct BuildInfo {
    let channel: BuildChannel
    /// The short git commit the binary was built from (e.g. "a1b2c3d", "+" suffix when the
    /// tree was dirty) — matching the Mac's banner. Falls back to `CFBundleVersion` / "local"
    /// if the build phase couldn't resolve a hash.
    let buildLabel: String
    /// `CFBundleShortVersionString` when present, else `nil`.
    let version: String?

    /// Resolved once — none of this changes while the app is running.
    static let current = BuildInfo()

    init() {
        let info = Bundle.main.infoDictionary
        version = info?["CFBundleShortVersionString"] as? String
        // Prefer the stamped git commit (mirrors the Mac's GitCommit.hash); an empty or
        // "unknown" value means git wasn't available at build time, so fall back to the
        // bundle build number.
        let commit = info?["NucleicCommit"] as? String
        buildLabel = commit.flatMap { $0.isEmpty || $0 == "unknown" ? nil : $0 }
            ?? (info?["CFBundleVersion"] as? String)
            ?? "local"
        channel = Self.detectChannel(stamped: info?["NucleicChannel"] as? String)
    }

    /// Prefer the archive-time stamp (mirrors the Mac's `NUCLEIC_CHANNEL` build setting);
    /// fall back to what the runtime can tell on its own.
    private static func detectChannel(stamped: String?) -> BuildChannel {
        switch stamped?.lowercased() {
        case "dev", "local": return .local
        case "canary": return .canary
        case "beta": return .beta
        case "rc": return .releaseCandidate
        case "stable", "release": return .release
        default: break
        }
        #if DEBUG
        return .local
        #else
        // TestFlight installs carry the sandbox receipt; App Store installs don't.
        if Bundle.main.appStoreReceiptURL?.lastPathComponent == "sandboxReceipt" { return .beta }
        return .release
        #endif
    }
}

/// Header strip warning that this is a non-release build — the same channel colors, icons,
/// and copy as the Mac's `BuildBanner`: red for local builds, canary-yellow for canary, blue
/// for beta, gold for a release candidate. The leading edge names the channel; the build
/// label and an all-caps "EXPERIMENTAL" badge sit on the trailing edge. Renders nothing for
/// a shipping App Store release.
struct BuildBanner: View {
    var info: BuildInfo = .current

    var body: some View {
        if let style = Style(channel: info.channel) {
            HStack(spacing: 8) {
                Image(systemName: style.icon)
                    .font(.system(size: 15, weight: .heavy))
                Text(style.label)
                    .font(.footnote.weight(.semibold))
                    .lineLimit(1)
                Spacer(minLength: 12)
                Text(info.buildLabel)
                    .font(.caption.monospaced())
                    .opacity(0.85)
                Text("EXPERIMENTAL")
                    .font(.caption2.weight(.heavy))
                    .tracking(0.9)
                    .padding(.horizontal, 6)
                    .padding(.vertical, 2)
                    .background(.white.opacity(0.16), in: .capsule)
            }
            .foregroundStyle(.white.opacity(0.92))
            .padding(.horizontal, 12)
            .padding(.vertical, 5)
            .frame(maxWidth: .infinity)
            .background(style.tint.opacity(0.5))
            .accessibilityLabel(style.tooltip(version: info.version, build: info.buildLabel))
        }
    }

    /// Per-channel appearance — identical constants to the Mac. `nil` for `.release` so the
    /// banner disappears entirely.
    private struct Style {
        var tint: Color
        var label: String
        var icon: String

        init?(channel: BuildChannel) {
            switch channel {
            case .local:
                tint = Color(red: 0.78, green: 0.18, blue: 0.18)   // red
                label = "Local Development Build"
                icon = "hammer.fill"
            case .canary:
                tint = Color(red: 1.00, green: 0.87, blue: 0.00)   // bright canary yellow
                label = "Canary Build"
                icon = "bell.and.waves.left.and.right.fill"
            case .beta:
                tint = Color(red: 0.13, green: 0.40, blue: 0.86)   // blue
                label = "Public Beta"
                icon = "person.3.fill"
            case .releaseCandidate:
                tint = Color(red: 0.83, green: 0.65, blue: 0.12)   // gold
                label = "Release Candidate"
                icon = "checkmark.seal.fill"
            case .release:
                return nil
            }
        }

        func tooltip(version: String?, build: String) -> String {
            let v = version.map { "\($0) " } ?? ""
            return "\(label) — \(v)commit \(build). Not a release build."
        }
    }
}

/// A slim strip shown while the app is in offline demo mode, so sample data is never mistaken
/// for a live connection to a Mac. Sits under the `BuildBanner` in `RootView`.
struct DemoBanner: View {
    @EnvironmentObject var store: RemoteStore

    var body: some View {
        if store.demoMode {
            HStack(spacing: 8) {
                Image(systemName: "play.circle.fill").font(.system(size: 14, weight: .bold))
                Text("Demo — sample data, no Mac connected")
                    .font(.footnote.weight(.semibold))
                    .lineLimit(1)
                Spacer(minLength: 8)
                Text("DEMO")
                    .font(.caption2.weight(.heavy))
                    .tracking(0.9)
                    .padding(.horizontal, 6)
                    .padding(.vertical, 2)
                    .background(.white.opacity(0.18), in: .capsule)
            }
            .foregroundStyle(.white.opacity(0.95))
            .padding(.horizontal, 12)
            .padding(.vertical, 5)
            .frame(maxWidth: .infinity)
            .background(Color(red: 0.36, green: 0.36, blue: 0.42))
            .accessibilityLabel("Demo mode — sample data, not connected to a Mac.")
        }
    }
}
