import SwiftUI

/// Gates the whole UI on iCloud availability. Files are the source of truth, so
/// there is no meaningful app without iCloud — we never fall back to local-only.
/// Mac-native counterpart to `RootGateView` (iOS): same states and brand look,
/// with System Settings-flavored copy instead of the Settings app.
struct MacRootGateView: View {
    @Environment(SyncEngine.self) private var syncEngine

    var body: some View {
        Group {
            switch syncEngine.iCloudStatus {
            case .checking:
                MacICloudCheckingView()
            case .available:
                MacContentView()
            case .unavailable:
                MacICloudRequiredView { Task { await syncEngine.connect() } }
            }
        }
    }
}

// MARK: - Brand palette (sampled from the app icon)

private extension Color {
    static let brandPurpleLight = Color(red: 0.627, green: 0.302, blue: 0.859) // #A04DDB
    static let brandPurpleMid   = Color(red: 0.478, green: 0.161, blue: 0.776) // #7A29C6
    static let brandPurpleDark  = Color(red: 0.333, green: 0.094, blue: 0.620) // #55189E
    /// Light teal — bright enough to stay legible on the purple gradient.
    static let brandTeal        = Color(red: 0.176, green: 0.831, blue: 0.749) // #2DD4BF
    /// Near-black teal ink, for text sitting on a filled teal button/badge.
    static let brandTealInk      = Color(red: 0.043, green: 0.157, blue: 0.145)
}

/// The full-bleed brand background shared by both gate screens.
private var brandBackground: some View {
    LinearGradient(
        colors: [.brandPurpleLight, .brandPurpleMid, .brandPurpleDark],
        startPoint: .topLeading,
        endPoint: .bottomTrailing
    )
    .ignoresSafeArea()
}

/// Parses inline Markdown and tints the **bold** runs teal, so key terms read
/// as highlights against the white body text.
private func brandHighlighted(_ markdown: String) -> AttributedString {
    guard var attributed = try? AttributedString(markdown: markdown) else {
        return AttributedString(markdown)
    }
    let emphasized = attributed.runs
        .filter { $0.inlinePresentationIntent?.contains(.stronglyEmphasized) == true }
        .map(\.range)
    for range in emphasized {
        attributed[range].foregroundColor = .brandTeal
    }
    return attributed
}

// MARK: - Checking

/// A branded, indeterminate connecting indicator: a rotating teal "comet" arc
/// around a steady iCloud glyph, over a faint track ring.
private struct MacConnectingIndicator: View {
    @State private var spin = false

    var body: some View {
        ZStack {
            Circle()
                .stroke(.white.opacity(0.12), lineWidth: 4.5)

            Circle()
                .trim(from: 0, to: 0.72)
                .stroke(
                    AngularGradient(
                        colors: [Color.brandTeal.opacity(0), Color.brandTeal],
                        center: .center
                    ),
                    style: StrokeStyle(lineWidth: 4.5, lineCap: .round)
                )
                .rotationEffect(.degrees(spin ? 360 : 0))

            Image(systemName: "icloud.fill")
                .font(.system(size: 30, weight: .medium))
                .foregroundStyle(Color.brandTeal)
        }
        .frame(width: 86, height: 86)
        .onAppear { spin = true }
        .animation(.linear(duration: 1.1).repeatForever(autoreverses: false), value: spin)
    }
}

/// Shown while we resolve the ubiquity container; branded so launch into the gate
/// (or the app) never flashes a bare system spinner. Resolving the container is an
/// opaque system call with no real ETA, so instead of a fake progress bar the copy
/// escalates with the wait.
private struct MacICloudCheckingView: View {
    @Environment(SyncEngine.self) private var syncEngine

    @State private var phase: Phase = .connecting
    @State private var canBail = false

    private enum Phase { case connecting, stillTrying, hint }

    var body: some View {
        ZStack {
            brandBackground
            VStack(spacing: 16) {
                MacConnectingIndicator()
                    .padding(.bottom, 4)

                Text(title)
                    .font(.headline)
                    .foregroundStyle(.white.opacity(0.9))

                if let detail {
                    Text(detail)
                        .font(.subheadline)
                        .multilineTextAlignment(.center)
                        .foregroundStyle(.white.opacity(0.72))
                        .transition(.opacity)
                }

                if phase == .hint {
                    Text(brandHighlighted("If you just turned it on, you can check **System Settings › your name › iCloud** while you wait."))
                        .font(.footnote)
                        .multilineTextAlignment(.center)
                        .foregroundStyle(.white.opacity(0.6))
                        .transition(.opacity)
                }

                // Escape hatch: we keep waiting as long as iCloud might still be
                // coming online, but a user who knows something's off can drop to
                // the setup gate instead of waiting out the full timeout.
                if canBail {
                    Button("iCloud not connecting? Set it up") {
                        syncEngine.abandonWaiting()
                    }
                    .font(.subheadline.weight(.semibold))
                    .foregroundStyle(Color.brandTeal)
                    .buttonStyle(.plain)
                    .padding(.top, 10)
                    .transition(.opacity)
                }
            }
            .padding(.horizontal, 36)
            .frame(maxWidth: 420)
            .animation(.easeInOut(duration: 0.4), value: phase)
            .animation(.easeInOut(duration: 0.4), value: canBail)
        }
        .task {
            try? await Task.sleep(for: .seconds(6))
            phase = .stillTrying
            try? await Task.sleep(for: .seconds(8))   // 14s in
            phase = .hint
            try? await Task.sleep(for: .seconds(14))  // 28s in
            canBail = true
        }
    }

    private var title: String {
        switch phase {
        case .connecting: "Connecting to iCloud…"
        case .stillTrying, .hint: "Still connecting…"
        }
    }

    private var detail: String? {
        switch phase {
        case .connecting: nil
        case .stillTrying, .hint: "This can take a moment right after you turn on iCloud Drive."
        }
    }
}

// MARK: - iCloud required

/// Explains — prominently, and explicitly *not* as a login — that Workouts keeps
/// the user's data in their own iCloud Drive, and walks them through enabling it
/// via System Settings.
private struct MacICloudRequiredView: View {
    let onCheckAgain: () -> Void

    @Environment(\.openURL) private var openURL

    private let learnMoreURL = URL(string: "https://indie.rzen.dev/support/icloud-drive")!

    var body: some View {
        ZStack {
            brandBackground

            ScrollView {
                VStack(spacing: 28) {
                    icon
                    headline
                    steps
                    notALoginNote
                    actions
                }
                .padding(.horizontal, 24)
                .padding(.top, 20)
                .padding(.bottom, 40)
                .frame(maxWidth: 480)
                .frame(maxWidth: .infinity)
            }
        }
    }

    private var icon: some View {
        Image(systemName: "lock.icloud.fill")
            .font(.system(size: 52, weight: .regular))
            .foregroundStyle(Color.brandTeal)
            .frame(width: 112, height: 112)
            .background(.white.opacity(0.08), in: Circle())
            .overlay(Circle().strokeBorder(.white.opacity(0.14), lineWidth: 1))
            .padding(.top, 12)
    }

    private var headline: some View {
        VStack(spacing: 12) {
            Text("Your workouts live\nin your iCloud")
                .font(.system(.largeTitle, design: .rounded, weight: .bold))
                .multilineTextAlignment(.center)
                .foregroundStyle(.white)

            Text(brandHighlighted("Workouts has no account and no server. Everything you create is saved as files in **your own iCloud Drive** — synced across your devices by Apple, and private to you. Not even the developer can see it."))
                .font(.callout)
                .multilineTextAlignment(.center)
                .foregroundStyle(.white.opacity(0.85))
        }
    }

    private var steps: some View {
        VStack(alignment: .leading, spacing: 0) {
            stepRow(1, "Open **System Settings** and click your name at the top")
            stepDivider
            stepRow(2, "Choose **iCloud** and make sure you're signed in")
            stepDivider
            stepRow(3, "Turn on **iCloud Drive**")
        }
        .background(.white.opacity(0.08), in: RoundedRectangle(cornerRadius: 18))
        .overlay(
            RoundedRectangle(cornerRadius: 18)
                .strokeBorder(.white.opacity(0.12), lineWidth: 1)
        )
    }

    private func stepRow(_ number: Int, _ markdown: String) -> some View {
        HStack(spacing: 14) {
            Text("\(number)")
                .font(.system(.subheadline, design: .rounded, weight: .bold))
                .foregroundStyle(Color.brandTealInk)
                .frame(width: 26, height: 26)
                .background(Color.brandTeal, in: Circle())
            Text(brandHighlighted(markdown))
                .font(.subheadline)
                .foregroundStyle(.white.opacity(0.92))
                .frame(maxWidth: .infinity, alignment: .leading)
        }
        .padding(.vertical, 14)
        .padding(.horizontal, 16)
    }

    private var stepDivider: some View {
        Rectangle()
            .fill(.white.opacity(0.1))
            .frame(height: 1)
            .padding(.leading, 56)
    }

    private var notALoginNote: some View {
        HStack(alignment: .firstTextBaseline, spacing: 9) {
            Image(systemName: "checkmark.shield.fill")
                .font(.footnote)
                .foregroundStyle(Color.brandTeal)
            Text("This isn't an app login. There's no account and no password to create — Workouts simply uses the iCloud already built into your Mac.")
                .font(.footnote)
                .foregroundStyle(.white.opacity(0.7))
                .frame(maxWidth: .infinity, alignment: .leading)
        }
    }

    private var actions: some View {
        VStack(spacing: 14) {
            Button(action: onCheckAgain) {
                Text("Check Again")
                    .font(.headline)
                    .foregroundStyle(Color.brandTealInk)
                    .frame(maxWidth: .infinity)
                    .padding(.vertical, 15)
                    .background(Color.brandTeal, in: Capsule())
            }
            .buttonStyle(.plain)

            Button("Why does Workouts need iCloud?") {
                openURL(learnMoreURL)
            }
            .font(.subheadline.weight(.semibold))
            .foregroundStyle(Color.brandTeal)
            .buttonStyle(.plain)
        }
        .padding(.top, 4)
    }
}
