//
//  InstanceLoginView.swift
//  Yattee
//
//  Shared login sheet for Invidious and Piped accounts.
//

import SwiftUI

struct InstanceLoginView: View {
    let instance: Instance
    let onLoginSuccess: (String) -> Void

    @Environment(\.dismiss) private var dismiss
    @Environment(\.appEnvironment) private var appEnvironment

    @State private var username = ""
    @State private var password = ""
    @State private var isLoading = false
    @State private var errorMessage: String?

    var body: some View {
        #if os(tvOS)
        TVSidebarDetailContainer(systemImage: "person.badge.key", title: String(localized: "login.title")) {
            formContent
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(Color.black.ignoresSafeArea())
        .accessibilityIdentifier("instance.login.view")
        #else
        NavigationStack {
            formContent
                .navigationTitle(String(localized: "login.title"))
                #if os(iOS)
                .navigationBarTitleDisplayMode(.inline)
                #endif
                .toolbar {
                    ToolbarItem(placement: .cancellationAction) {
                        Button(String(localized: "common.cancel")) {
                            dismiss()
                        }
                    }
                }
                .accessibilityIdentifier("instance.login.view")
        }
        #if os(macOS)
        .frame(minWidth: 450, minHeight: 350)
        #endif
        #endif
    }

    private var formContent: some View {
        Form {
            Section {
                #if os(tvOS)
                TVSettingsTextField(title: usernameFieldLabel, text: $username)
                TVSettingsTextField(title: String(localized: "login.password"), text: $password, isSecure: true)
                #else
                TextField(usernameFieldLabel, text: $username)
                    .textContentType(.username)
                    #if os(iOS)
                    .textInputAutocapitalization(.never)
                    #endif
                    .autocorrectionDisabled()
                    .accessibilityIdentifier("instance.login.usernameField")

                SecureField(String(localized: "login.password"), text: $password)
                    .textContentType(.password)
                    .accessibilityIdentifier("instance.login.passwordField")
                #endif
            } header: {
                Text(String(localized: "login.header.credentials"))
            } footer: {
                Text(footerText)
            }

            if let error = errorMessage {
                Section {
                    Label(error, systemImage: "exclamationmark.triangle")
                        .foregroundStyle(.red)
                        .accessibilityIdentifier("instance.login.error")
                }
            }

            Section {
                Button {
                    login()
                } label: {
                    if isLoading {
                        HStack {
                            ProgressView()
                                .controlSize(.small)
                            Text(String(localized: "login.loggingIn"))
                        }
                    } else {
                        Text(String(localized: "login.signIn"))
                    }
                }
                .disabled(username.isEmpty || password.isEmpty || isLoading)
                .accessibilityIdentifier("instance.login.submitButton")
                #if os(tvOS)
                .buttonStyle(TVSettingsButtonStyle())
                #endif
            }
        }
        #if os(iOS)
        .scrollDismissesKeyboard(.interactively)
        #endif
    }

    // MARK: - Computed Properties

    /// Returns the appropriate label for the username field based on instance type.
    private var usernameFieldLabel: String {
        switch instance.type {
        case .piped:
            return String(localized: "login.username")
        case .invidious:
            return String(localized: "login.email")
        default:
            return String(localized: "login.username")
        }
    }

    /// Returns the appropriate footer text based on instance type.
    private var footerText: String {
        switch instance.type {
        case .piped:
            return String(localized: "login.footer.pipedAccount \(instance.displayName)")
        case .invidious:
            return String(localized: "login.footer.invidiousAccount \(instance.displayName)")
        default:
            return ""
        }
    }

    // MARK: - Actions

    private func login() {
        guard let appEnvironment else { return }

        isLoading = true
        errorMessage = nil

        Task {
            do {
                let credential = try await performLogin(appEnvironment: appEnvironment)

                await MainActor.run {
                    onLoginSuccess(credential)
                    dismiss()
                }
            } catch APIError.unauthorized {
                await MainActor.run {
                    errorMessage = String(localized: "login.error.invalidCredentials")
                    isLoading = false
                }
            } catch {
                await MainActor.run {
                    errorMessage = error.localizedDescription
                    isLoading = false
                }
            }
        }
    }

    /// Performs the login based on instance type.
    /// - Returns: The credential (SID for Invidious, token for Piped)
    private func performLogin(appEnvironment: AppEnvironment) async throws -> String {
        // If the instance sits behind an HTTP Basic Auth reverse proxy, the login
        // POST must carry that proxy's Authorization header too — otherwise the
        // request 401s before reaching the upstream login endpoint. Bake the
        // header into a fresh per-instance HTTPClient.
        let basicAuthHeader = appEnvironment.basicAuthCredentialsManager.basicAuthHeader(for: instance)
        let extraHeaders: [String: String]? = basicAuthHeader.map { ["Authorization": $0] }

        let httpClient: HTTPClient
        if let basicAuthHeader {
            httpClient = appEnvironment.httpClientFactory.createClient(for: instance)
            await httpClient.setDefaultHeaders(["Authorization": basicAuthHeader])
        } else {
            httpClient = appEnvironment.httpClient
        }

        switch instance.type {
        case .invidious:
            // InvidiousAPI.login uses its own URLSession (to handle redirect/Set-Cookie),
            // so it doesn't inherit defaultHeaders from the injected HTTPClient. Pass
            // the basic-auth header explicitly so the login POST passes the proxy.
            let api = InvidiousAPI(httpClient: httpClient)
            return try await api.login(email: username, password: password, instance: instance, extraHeaders: extraHeaders)

        case .piped:
            // PipedAPI.login uses httpClient.fetch which DOES inherit defaultHeaders,
            // so the basic-auth header on the per-instance client is sufficient.
            let api = PipedAPI(httpClient: httpClient)
            return try await api.login(username: username, password: password, instance: instance)

        default:
            throw APIError.notSupported
        }
    }
}

// MARK: - Preview

#Preview("Invidious") {
    InstanceLoginView(
        instance: Instance(type: .invidious, url: URL(string: "https://invidious.example.com")!)
    ) { _ in }
    .appEnvironment(.preview)
}

#Preview("Piped") {
    InstanceLoginView(
        instance: Instance(type: .piped, url: URL(string: "https://piped.example.com")!)
    ) { _ in }
    .appEnvironment(.preview)
}
