import SwiftUI

/// Connection configuration. Doubles as initial setup (no config yet) and the
/// in-app Settings tab. Credentials are entered on the Login screen, not here.
struct SettingsView: View {
    let isInitialSetup: Bool
    @Environment(AppEnvironment.self) private var env
    @Environment(\.dismiss) private var dismiss

    @State private var urlString = "https://"
    @State private var apiVersion = "v1"
    @State private var databaseId = ""

    @State private var testPhase: LoadPhase = .idle
    @State private var testResult: String?
    @State private var saveError: String?

    var body: some View {
        Form {
            Section {
                TextField("https://host[/api]", text: $urlString)
                    .textInputAutocapitalization(.never)
                    .autocorrectionDisabled()
                    .keyboardType(.URL)
                TextField("API version", text: $apiVersion)
                    .textInputAutocapitalization(.never)
                    .autocorrectionDisabled()
            } header: {
                Text("Server")
            } footer: {
                Text("Host or origin, e.g. https://mcms.lab.svorka.net — “/api” is appended automatically unless you enter a path. Endpoints are v1.")
            }

            Section("Database (optional)") {
                TextField("Database ID", text: $databaseId)
                    .textInputAutocapitalization(.never)
                    .autocorrectionDisabled()
            }

            Section {
                Button {
                    Task { await runTest() }
                } label: {
                    HStack {
                        Text("Test connection")
                        Spacer()
                        switch testPhase {
                        case .loading: ProgressView()
                        case .loaded: Image(systemName: "checkmark.circle.fill").foregroundStyle(.green)
                        case .failed: Image(systemName: "xmark.circle.fill").foregroundStyle(.red)
                        case .idle: EmptyView()
                        }
                    }
                }
                .disabled(!canSave)

                if let testResult {
                    Text(testResult).font(.footnote).foregroundStyle(.secondary)
                }
            } footer: {
                if case .failed(let msg) = testPhase {
                    Text(msg).foregroundStyle(.red)
                }
            }

            if !isInitialSetup {
                Section {
                    Button("Sign out", role: .destructive) {
                        Task { await env.signOut() }
                    }
                }
            }

            if let saveError {
                Section { Text(saveError).foregroundStyle(.red) }
            }
        }
        .navigationTitle(isInitialSetup ? "Set up connection" : "Settings")
        .toolbar {
            ToolbarItem(placement: .confirmationAction) {
                Button("Save") { save() }.disabled(!canSave)
            }
        }
        .onAppear(perform: prefill)
    }

    private var canSave: Bool {
        Self.normalizedBaseURL(urlString) != nil && !apiVersion.trimmingCharacters(in: .whitespaces).isEmpty
    }

    private func prefill() {
        guard let config = env.configuration else { return }
        urlString = config.baseURL.absoluteString
        apiVersion = config.apiVersion
        databaseId = config.databaseId ?? ""
    }

    private func makeConfig() -> APIConfiguration? {
        // TLS uses system trust only (no self-signed bypass); trustPolicy defaults to .system.
        guard let url = Self.normalizedBaseURL(urlString), url.host != nil else { return nil }
        return APIConfiguration(
            baseURL: url,
            apiVersion: apiVersion.trimmingCharacters(in: .whitespaces),
            databaseId: databaseId.isEmpty ? nil : databaseId
        )
    }

    /// Normalizes the entered server URL: requires scheme + host, trims any
    /// trailing slash, and defaults the path to `/api` when none is given — every
    /// MCMS REST path lives under `/api` (dev guide). A reverse proxy mounted
    /// elsewhere can still be entered with an explicit path.
    static func normalizedBaseURL(_ raw: String) -> URL? {
        let trimmed = raw.trimmingCharacters(in: .whitespacesAndNewlines)
        guard var comps = URLComponents(string: trimmed),
              comps.scheme != nil, let host = comps.host, !host.isEmpty else { return nil }
        var path = comps.path
        while path.hasSuffix("/") { path.removeLast() }
        if path.isEmpty { path = "/api" }
        comps.path = path
        return comps.url
    }

    private func save() {
        guard let config = makeConfig() else {
            saveError = "Enter a valid URL including scheme (https://)."
            return
        }
        saveError = nil
        env.configure(config)
        if !isInitialSetup { dismiss() }
    }

    private func runTest() async {
        guard let config = makeConfig() else { return }
        testPhase = .loading
        testResult = nil
        do {
            let result = try await env.probe(config)
            testResult = "Connected · \(result)"
            testPhase = .loaded
        } catch {
            testPhase = .failed((error as? APIError)?.localizedDescription ?? error.localizedDescription)
        }
    }
}
