import LocalAuthentication
import SwiftUI

/// Password unlock screen matching rosetta-android design.
struct UnlockView: View {
    let onUnlocked: () -> Void
    var onCreateNewAccount: (() -> Void)?

    @State private var password = ""
    @State private var isUnlocking = false
    @State private var errorMessage: String?
    // Biometric unlock
    @State private var biometricTriggered = false
    // Avatar
    @State private var avatarImage: UIImage?
    // Multi-account picker (desktop parity: DiceDropdown)
    @State private var showAccountPicker = false

    // Staggered fade-in animation
    @State private var showAvatar = false
    @State private var showTitle = false
    @State private var showSubtitle = false
    @State private var showInput = false
    @State private var showButton = false
    @State private var showFooter = false

    private var account: Account? { AccountManager.shared.currentAccount }

    private var publicKey: String {
        account?.publicKey ?? ""
    }

    /// Initials from display name, falling back to first 2 chars of public key.
    private var avatarText: String {
        RosettaColors.initials(name: account?.displayName ?? "", publicKey: publicKey)
    }

    private var avatarColorIndex: Int {
        RosettaColors.avatarColorIndex(for: account?.displayName ?? "", publicKey: publicKey)
    }

    /// Short public key — 7 characters like Android (e.g. "0325a4d").
    private var shortPublicKey: String {
        guard publicKey.count >= 7 else { return publicKey }
        return String(publicKey.prefix(7))
    }

    /// Display name or short public key.
    private var displayTitle: String {
        let name = account?.displayName ?? ""
        if !name.isEmpty { return name }
        return shortPublicKey
    }

    /// Whether biometric unlock is available and enabled for this account.
    private var canUseBiometric: Bool {
        BiometricAuthManager.shared.canUseBiometric(forAccount: publicKey)
    }

    var body: some View {
        ZStack {
            RosettaColors.authBackground
                .ignoresSafeArea()

            ScrollView {
                VStack(spacing: 0) {
                    Spacer().frame(height: 80)

                    // Avatar
                    AvatarView(
                        initials: avatarText,
                        colorIndex: avatarColorIndex,
                        size: 100,
                        isSavedMessages: false,
                        image: avatarImage
                    )
                    .opacity(showAvatar ? 1 : 0)
                    .scaleEffect(showAvatar ? 1 : 0.8)

                    Spacer().frame(height: 20)

                    // Display name (or short public key fallback) + account switcher
                    HStack(spacing: 8) {
                        Text(displayTitle)
                            .font(.system(size: 24, weight: .bold))
                            .foregroundStyle(RosettaColors.Adaptive.text)

                        // Desktop parity: DiceDropdown arrow icon for multi-account
                        if AccountManager.shared.hasMultipleAccounts {
                            Button {
                                showAccountPicker = true
                            } label: {
                                Image(systemName: "arrow.left.arrow.right")
                                    .font(.system(size: 16, weight: .medium))
                                    .foregroundStyle(RosettaColors.Adaptive.textSecondary)
                            }
                            .buttonStyle(.plain)
                        }
                    }
                    .opacity(showTitle ? 1 : 0)
                    .offset(y: showTitle ? 0 : 8)

                    Spacer().frame(height: 8)

                    // Subtitle — matching Android
                    Text("For unlock account enter password")
                        .font(.system(size: 15))
                        .foregroundStyle(RosettaColors.Adaptive.textSecondary)
                        .opacity(showSubtitle ? 1 : 0)
                        .offset(y: showSubtitle ? 0 : 8)

                    Spacer().frame(height: 40)

                    // Password input
                    passwordField
                        .padding(.horizontal, 24)
                        .opacity(showInput ? 1 : 0)
                        .offset(y: showInput ? 0 : 12)

                    Spacer().frame(height: 24)

                    // Enter button — matching onboarding style
                    unlockButton
                        .padding(.horizontal, 24)
                        .opacity(showButton ? 1 : 0)
                        .offset(y: showButton ? 0 : 12)

                    // Biometric button — shown when Face ID/Touch ID is available
                    if canUseBiometric {
                        biometricButton
                            .padding(.top, 16)
                            .opacity(showButton ? 1 : 0)
                            .offset(y: showButton ? 0 : 12)
                    }

                    Spacer().frame(height: 60)

                    // Footer — "You can also recover your password or create a new account."
                    footerView
                        .opacity(showFooter ? 1 : 0)

                    Spacer().frame(height: 40)
                }
            }
            .scrollDismissesKeyboard(.interactively)
        }
        .onAppear {
            avatarImage = AvatarRepository.shared.loadAvatar(publicKey: publicKey)
            startAnimations()
        }
        .task { await autoTriggerBiometric() }
        .confirmationDialog("Switch Account", isPresented: $showAccountPicker, titleVisibility: .visible) {
            ForEach(AccountManager.shared.allAccounts, id: \.publicKey) { account in
                let isActive = account.publicKey == publicKey
                Button(accountLabel(for: account)) {
                    if !isActive {
                        switchAccount(to: account.publicKey)
                    }
                }
                .disabled(isActive)
            }
            Button("Cancel", role: .cancel) {}
        }
    }
}

// MARK: - Password Field

private extension UnlockView {
    var passwordField: some View {
        VStack(alignment: .leading, spacing: 8) {
            GlassCard(cornerRadius: 14, fillOpacity: 0.08) {
                UnlockPasswordField(text: $password, onSubmit: { unlock() })
            }
            .overlay {
                RoundedRectangle(cornerRadius: 14)
                    .stroke(
                        errorMessage != nil ? RosettaColors.error : Color.clear,
                        lineWidth: 1
                    )
            }

            if let error = errorMessage {
                Text(error)
                    .font(.system(size: 14))
                    .foregroundStyle(RosettaColors.error)
                    .padding(.leading, 4)
                    .transition(.opacity)
            }
        }
    }
}

// MARK: - Unlock Button

private extension UnlockView {
    var unlockButton: some View {
        Button(action: unlock) {
            Group {
                if isUnlocking {
                    ProgressView()
                        .tint(.white)
                        .scaleEffect(0.9)
                } else {
                    Text("Enter")
                        .font(.system(size: 16, weight: .semibold))
                }
            }
            .foregroundStyle(.white)
            .frame(maxWidth: .infinity)
            .frame(height: 56)
        }
        .buttonStyle(RosettaPrimaryButtonStyle())
        .shine()
        .disabled(isUnlocking)
    }

    /// Desktop parity: fingerprint/biometric icon instead of lock.
    private var biometricIconName: String {
        BiometricAuthManager.shared.biometricIconName
    }

    /// Face ID / Touch ID button — allows user to re-trigger biometric unlock.
    var biometricButton: some View {
        Button {
            triggerBiometricUnlock()
        } label: {
            HStack(spacing: 8) {
                Image(systemName: biometricIconName)
                    .font(.system(size: 20))
                Text("Unlock with \(BiometricAuthManager.shared.biometricName)")
                    .font(.system(size: 15, weight: .medium))
            }
            .foregroundStyle(RosettaColors.Adaptive.textSecondary)
        }
        .buttonStyle(.plain)
        .disabled(isUnlocking)
    }
}

// MARK: - Footer

private extension UnlockView {
    var footerView: some View {
        VStack(spacing: 4) {
            HStack(spacing: 0) {
                Text("You can also ")
                    .foregroundStyle(RosettaColors.Adaptive.textSecondary)

                Button {
                    onCreateNewAccount?()
                } label: {
                    Text("recover your password")
                        .fontWeight(.semibold)
                        .foregroundStyle(RosettaColors.primaryBlue)
                }
                .buttonStyle(.plain)

                Text(" or")
                    .foregroundStyle(RosettaColors.Adaptive.textSecondary)
            }
            .font(.system(size: 15))

            HStack(spacing: 0) {
                Text("create a ")
                    .foregroundStyle(RosettaColors.Adaptive.textSecondary)

                Button {
                    onCreateNewAccount?()
                } label: {
                    Text("new account.")
                        .fontWeight(.semibold)
                        .foregroundStyle(RosettaColors.primaryBlue)
                }
                .buttonStyle(.plain)
            }
            .font(.system(size: 15))
        }
        .multilineTextAlignment(.center)
        .padding(.horizontal, 32)
    }
}

// MARK: - Actions

private extension UnlockView {
    func unlock() {
        guard !isUnlocking else { return }
        guard !password.isEmpty else {
            withAnimation(.easeInOut(duration: 0.2)) {
                errorMessage = "Please enter your password."
            }
            return
        }
        isUnlocking = true
        errorMessage = nil

        let enteredPassword = password
        let accountKey = publicKey

        Task {
            do {
                try await SessionManager.shared.startSession(password: enteredPassword)

                // If biometric is enabled, update the stored password
                // (in case user changed password and re-entered it manually)
                let biometric = BiometricAuthManager.shared
                if biometric.isBiometricEnabled(forAccount: accountKey) {
                    try? biometric.savePassword(enteredPassword, forAccount: accountKey)
                }

                onUnlocked()
            } catch let sessionError as SessionManager.StartSessionError {
                withAnimation(.easeInOut(duration: 0.2)) {
                    errorMessage = unlockMessage(for: sessionError)
                }
                isUnlocking = false
            } catch {
                withAnimation(.easeInOut(duration: 0.2)) {
                    errorMessage = unlockMessage(for: error)
                }
                isUnlocking = false
            }
        }
    }

    /// Label for account in the picker dialog.
    func accountLabel(for account: Account) -> String {
        let name = account.displayName ?? ""
        if !name.isEmpty { return name }
        guard account.publicKey.count >= 7 else { return account.publicKey }
        return String(account.publicKey.prefix(7))
    }

    /// Switches active account — resets password/error/biometric state, reloads avatar.
    /// Desktop parity: `selectAccountToLoginDice()` in `Lockscreen.tsx`.
    func switchAccount(to newPublicKey: String) {
        AccountManager.shared.setActiveAccount(publicKey: newPublicKey)

        // Reset input state
        password = ""
        errorMessage = nil
        isUnlocking = false
        biometricTriggered = false

        // Reload avatar for the new account
        avatarImage = AvatarRepository.shared.loadAvatar(publicKey: newPublicKey)

        // Auto-trigger biometric for the new account if available
        Task {
            await autoTriggerBiometric()
        }
    }

    func startAnimations() {
        withAnimation(.easeOut(duration: 0.3)) { showAvatar = true }
        withAnimation(.easeOut(duration: 0.3).delay(0.08)) { showTitle = true }
        withAnimation(.easeOut(duration: 0.3).delay(0.12)) { showSubtitle = true }
        withAnimation(.easeOut(duration: 0.3).delay(0.16)) { showInput = true }
        withAnimation(.easeOut(duration: 0.3).delay(0.20)) { showButton = true }
        withAnimation(.easeOut(duration: 0.3).delay(0.24)) { showFooter = true }
    }

    /// Auto-triggers biometric unlock after animations complete.
    func autoTriggerBiometric() async {
        // Don't trigger Face ID during an active call — CallKit handles the call UI.
        // Face ID fails in background anyway ("Caller is not running foreground").
        if CallKitManager.shared.hasPendingCall() ||
           CallManager.shared.uiState.phase != .idle {
            return
        }

        guard canUseBiometric, !biometricTriggered else { return }
        biometricTriggered = true

        // Wait for staggered animations to finish before showing Face ID prompt
        try? await Task.sleep(nanoseconds: 600_000_000)

        guard !isUnlocking else { return }
        await performBiometricUnlock()
    }

    /// Triggered by user tapping the biometric button.
    func triggerBiometricUnlock() {
        guard !isUnlocking else { return }
        Task {
            await performBiometricUnlock()
        }
    }

    /// Performs the biometric unlock flow: authenticate → load password → start session.
    func performBiometricUnlock() async {
        guard !isUnlocking else { return }
        isUnlocking = true
        errorMessage = nil

        do {
            let storedPassword = try await BiometricAuthManager.shared.unlockWithBiometric(
                forAccount: publicKey
            )
            try await SessionManager.shared.startSession(password: storedPassword)
            onUnlocked()
        } catch let error as BiometricError {
            isUnlocking = false
            // User cancelled — silently return to password input
            if case .cancelled = error { return }
            withAnimation(.easeInOut(duration: 0.2)) {
                errorMessage = error.localizedDescription
            }
        } catch {
            // SessionManager.startSession failed — stored password might be wrong
            withAnimation(.easeInOut(duration: 0.2)) {
                errorMessage = unlockMessage(for: error)
            }
            isUnlocking = false
        }
    }

    func unlockMessage(for error: Error) -> String {
        if let sessionError = error as? SessionManager.StartSessionError {
            switch sessionError {
            case .invalidCredentials:
                return "Wrong password. Please try again."
            case .databaseBootstrapFailed:
                return "Database migration failed. Please restart the app and try again."
            }
        }
        return "Wrong password. Please try again."
    }
}

// MARK: - UIKit Password Field

/// UITextField subclass with locked intrinsicContentSize.
/// Prevents layout propagation to SwiftUI when isSecureTextEntry toggles.
private final class UnlockTextField: UITextField {
    override var intrinsicContentSize: CGSize {
        CGSize(width: UIView.noIntrinsicMetric, height: 50)
    }

    override func textRect(forBounds bounds: CGRect) -> CGRect {
        bounds.inset(by: UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 46))
    }

    override func editingRect(forBounds bounds: CGRect) -> CGRect {
        textRect(forBounds: bounds)
    }

    override func rightViewRect(forBounds bounds: CGRect) -> CGRect {
        CGRect(x: bounds.width - 16 - 30, y: (bounds.height - 30) / 2, width: 30, height: 30)
    }

    override func placeholderRect(forBounds bounds: CGRect) -> CGRect {
        textRect(forBounds: bounds)
    }
}

/// Wraps UIKit UITextField with built-in eye toggle as rightView.
/// Toggle happens entirely in UIKit — no SwiftUI state, no body re-evaluation.
private struct UnlockPasswordField: UIViewRepresentable {
    @Binding var text: String
    var onSubmit: () -> Void

    func makeCoordinator() -> Coordinator { Coordinator(parent: self) }

    func makeUIView(context: Context) -> UnlockTextField {
        let tf = UnlockTextField()
        context.coordinator.textField = tf

        tf.isSecureTextEntry = true
        tf.font = .systemFont(ofSize: 16)
        tf.textColor = .label
        tf.tintColor = UIColor(RosettaColors.primaryBlue)
        tf.autocapitalizationType = .none
        tf.autocorrectionType = .no
        tf.spellCheckingType = .no
        tf.textContentType = .password
        tf.returnKeyType = .done
        tf.backgroundColor = .clear
        tf.setContentHuggingPriority(.required, for: .vertical)
        tf.setContentCompressionResistancePriority(.required, for: .vertical)

        tf.delegate = context.coordinator
        tf.addTarget(
            context.coordinator,
            action: #selector(Coordinator.textChanged(_:)),
            for: .editingChanged
        )
        tf.attributedPlaceholder = NSAttributedString(
            string: "Password",
            attributes: [.foregroundColor: UIColor.placeholderText]
        )

        // Eye toggle button — entirely UIKit, light weight for clean Mantine-like look
        let config = UIImage.SymbolConfiguration(pointSize: 14, weight: .thin)
        let eyeButton = UIButton(type: .system)
        eyeButton.setImage(UIImage(systemName: "eye", withConfiguration: config), for: .normal)
        eyeButton.tintColor = .secondaryLabel
        eyeButton.addTarget(
            context.coordinator,
            action: #selector(Coordinator.toggleSecure),
            for: .touchUpInside
        )
        eyeButton.frame = CGRect(x: 0, y: 0, width: 30, height: 30)
        eyeButton.accessibilityLabel = "Show password"
        tf.rightView = eyeButton
        tf.rightViewMode = .always

        return tf
    }

    func updateUIView(_ tf: UnlockTextField, context: Context) {
        context.coordinator.parent = self
        if tf.text != text { tf.text = text }
    }

    func sizeThatFits(
        _ proposal: ProposedViewSize,
        uiView: UnlockTextField,
        context: Context
    ) -> CGSize? {
        CGSize(width: proposal.width ?? 200, height: 50)
    }

    final class Coordinator: NSObject, UITextFieldDelegate {
        var parent: UnlockPasswordField
        weak var textField: UnlockTextField?

        init(parent: UnlockPasswordField) { self.parent = parent }

        @objc func textChanged(_ tf: UITextField) {
            parent.text = tf.text ?? ""
        }

        @objc func toggleSecure() {
            guard let tf = textField else { return }
            UIView.performWithoutAnimation {
                let existingText = tf.text
                tf.isSecureTextEntry.toggle()
                tf.text = ""
                tf.text = existingText

                let imageName = tf.isSecureTextEntry ? "eye" : "eye.slash"
                let config = UIImage.SymbolConfiguration(pointSize: 14, weight: .thin)
                let button = tf.rightView as? UIButton
                button?.setImage(
                    UIImage(systemName: imageName, withConfiguration: config),
                    for: .normal
                )
                button?.accessibilityLabel = tf.isSecureTextEntry
                    ? "Show password"
                    : "Hide password"
            }
        }

        func textFieldShouldReturn(_ textField: UITextField) -> Bool {
            parent.onSubmit()
            return true
        }
    }
}
