//
//  LegacyDataImportView.swift
//  Yattee
//
//  View for reviewing and re-creating accounts and sources from the legacy v1 app.
//

import SwiftUI

struct LegacyAccountsImportView: View {
    @Environment(\.dismiss) private var dismiss
    @Environment(\.appEnvironment) private var appEnvironment

    var showsDoneButton = true

    @State private var accountItems: [LegacyAccountImportItem] = []
    @State private var instanceItems: [LegacyInstanceImportItem] = []
    @State private var rowStates: [String: LegacyAccountRowState] = [:]
    @State private var isLoading = true
    @State private var pendingRemoval: PendingRemoval?
    @State private var importSuccessTitle = ""
    @State private var importedInstanceName = ""
    @State private var showingImportSuccess = false

    private var legacyMigrationService: LegacyDataMigrationService? {
        appEnvironment?.legacyMigrationService
    }

    private var isEmpty: Bool {
        accountItems.isEmpty && instanceItems.isEmpty
    }

    var body: some View {
        Group {
            if isLoading {
                ProgressView()
                    .controlSize(.large)
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
            } else if isEmpty {
                emptyState
            } else {
                contentList
            }
        }
        #if !os(tvOS)
        // On tvOS the title comes from the TVSidebarDetailContainer sidebar;
        // a navigationTitle would render as a giant ghost behind the form.
        .navigationTitle(String(localized: "migration.accounts.title"))
        #endif
        #if os(iOS)
        .navigationBarTitleDisplayMode(.inline)
        #endif
        .opaqueSettingsFormBackground()
        .toolbar {
            #if !os(tvOS)
            if showsDoneButton {
                ToolbarItem(placement: .cancellationAction) {
                    Button(String(localized: "common.done")) {
                        dismiss()
                    }
                }
            }
            #endif
        }
        .task {
            loadLegacyData()
        }
        .confirmationDialog(
            pendingRemoval?.confirmationTitle ?? "",
            isPresented: Binding(
                get: { pendingRemoval != nil },
                set: { if !$0 { pendingRemoval = nil } }
            ),
            titleVisibility: .visible,
            presenting: pendingRemoval
        ) { removal in
            Button(String(localized: "migration.accounts.remove.confirm"), role: .destructive) {
                confirmRemoval(removal)
            }
            Button(String(localized: "common.cancel"), role: .cancel) {}
        } message: { removal in
            Text(String(localized: "migration.accounts.remove.message \(removal.displayName)"))
        }
        .alert(importSuccessTitle, isPresented: $showingImportSuccess) {
            Button(String(localized: "common.ok"), role: .cancel) {}
        } message: {
            Text(importedInstanceName)
        }
    }

    private var contentList: some View {
        Form {
            if !accountItems.isEmpty {
                Section {
                    ForEach(accountItems) { item in
                        LegacyAccountImportRow(
                            item: item,
                            state: stateBinding(for: item)
                        ) {
                            importLegacyAccount(item)
                        } onRemove: {
                            pendingRemoval = .account(item)
                        }
                    }
                } header: {
                    Text(String(localized: "migration.accounts.section"))
                } footer: {
                    Text(String(localized: "migration.accounts.footer"))
                }
            }

            if !instanceItems.isEmpty {
                Section {
                    ForEach(instanceItems) { item in
                        LegacyInstanceImportRow(item: item) {
                            importLegacyInstance(item)
                        } onRemove: {
                            pendingRemoval = .instance(item)
                        }
                    }
                } header: {
                    Text(String(localized: "migration.sources.section"))
                } footer: {
                    Text(String(localized: "migration.sources.footer"))
                }
            }
        }
        #if os(iOS)
        .scrollDismissesKeyboard(.interactively)
        #endif
        #if os(macOS)
        .formStyle(.grouped)
        #endif
    }

    private var emptyState: some View {
        ContentUnavailableView(
            String(localized: "migration.accounts.empty.title"),
            systemImage: "person.badge.key",
            description: Text(String(localized: "migration.accounts.empty.description"))
        )
        .frame(maxWidth: .infinity, maxHeight: .infinity)
    }

    private func loadLegacyData() {
        let loadedAccounts = legacyMigrationService?.parseLegacyAccountsForImport() ?? []
        accountItems = loadedAccounts
        instanceItems = legacyMigrationService?.parseLegacyInstancesForImport() ?? []
        for item in loadedAccounts where rowStates[item.legacyAccountID] == nil {
            rowStates[item.legacyAccountID] = LegacyAccountRowState(username: item.username)
        }
        isLoading = false
    }

    private func stateBinding(for item: LegacyAccountImportItem) -> Binding<LegacyAccountRowState> {
        Binding {
            rowStates[item.legacyAccountID] ?? LegacyAccountRowState(username: item.username)
        } set: { newValue in
            rowStates[item.legacyAccountID] = newValue
        }
    }

    private func importLegacyAccount(_ item: LegacyAccountImportItem) {
        guard let service = legacyMigrationService else { return }
        var state = rowStates[item.legacyAccountID] ?? LegacyAccountRowState(username: item.username)
        state.isImporting = true
        state.errorMessage = nil
        rowStates[item.legacyAccountID] = state

        Task {
            do {
                let importedInstance = try await service.importLegacyAccount(
                    item,
                    username: state.username,
                    password: state.password
                )
                importSuccessTitle = String(localized: "migration.accounts.imported.title")
                importedInstanceName = importedInstance.displayName
                showingImportSuccess = true
                accountItems.removeAll { $0.legacyAccountID == item.legacyAccountID }
                rowStates.removeValue(forKey: item.legacyAccountID)
            } catch APIError.unauthorized {
                setImportError(String(localized: "login.error.invalidCredentials"), for: item)
            } catch {
                setImportError(error.localizedDescription, for: item)
            }
        }
    }

    private func importLegacyInstance(_ item: LegacyInstanceImportItem) {
        guard let service = legacyMigrationService else { return }
        let importedInstance = service.importLegacyInstance(item)
        importSuccessTitle = String(localized: "migration.sources.imported.title")
        importedInstanceName = importedInstance.displayName
        showingImportSuccess = true
        instanceItems.removeAll { $0.legacyInstanceID == item.legacyInstanceID }
    }

    private func setImportError(_ message: String, for item: LegacyAccountImportItem) {
        var state = rowStates[item.legacyAccountID] ?? LegacyAccountRowState(username: item.username)
        state.isImporting = false
        state.errorMessage = message
        rowStates[item.legacyAccountID] = state
    }

    private func confirmRemoval(_ removal: PendingRemoval) {
        switch removal {
        case .account(let item):
            legacyMigrationService?.removeLegacyAccount(item)
            accountItems.removeAll { $0.legacyAccountID == item.legacyAccountID }
            rowStates.removeValue(forKey: item.legacyAccountID)
        case .instance(let item):
            legacyMigrationService?.removeLegacyInstance(item)
            instanceItems.removeAll { $0.legacyInstanceID == item.legacyInstanceID }
        }
    }
}

// MARK: - Pending Removal

private enum PendingRemoval: Identifiable {
    case account(LegacyAccountImportItem)
    case instance(LegacyInstanceImportItem)

    var id: String {
        switch self {
        case .account(let item):
            return "account:\(item.id)"
        case .instance(let item):
            return "instance:\(item.id)"
        }
    }

    var displayName: String {
        switch self {
        case .account(let item):
            return item.displayName
        case .instance(let item):
            return item.instanceDisplayName
        }
    }

    var confirmationTitle: String {
        switch self {
        case .account:
            return String(localized: "migration.accounts.remove.title")
        case .instance:
            return String(localized: "migration.sources.remove.title")
        }
    }
}

// MARK: - Account Row

private struct LegacyAccountImportRow: View {
    let item: LegacyAccountImportItem
    @Binding var state: LegacyAccountRowState
    let onImport: () -> Void
    let onRemove: () -> Void

    private var canImport: Bool {
        !state.username.isEmpty && !state.password.isEmpty && !state.isImporting
    }

    private var infoHeader: some View {
        HStack(alignment: .top, spacing: 12) {
            Image(systemName: legacyInstanceIcon(for: item.instanceType))
                .font(.title2)
                .foregroundStyle(.secondary)
                .frame(width: legacyRowIconWidth)

            VStack(alignment: .leading, spacing: 3) {
                Text(item.displayName)
                    .font(.headline)

                Text(item.instanceDisplayName)
                    .font(.subheadline)
                    .foregroundStyle(.secondary)

                Text(item.url.host ?? item.url.absoluteString)
                    .font(.caption)
                    .foregroundStyle(.secondary)
                    .lineLimit(1)
            }

            Spacer()
        }
    }

    var body: some View {
        #if os(tvOS)
        // On tvOS a Form row is a single focusable unit, so packing the whole card
        // into one row makes the first button (Remove) swallow every click.
        // Emit each interactive element as its own row instead.
        infoHeader
            .padding(.vertical, 8)

        credentialsFields

        if let errorMessage = state.errorMessage {
            Label(errorMessage, systemImage: "exclamationmark.triangle")
                .font(.caption)
                .foregroundStyle(.red)
        }

        Button(action: onImport) {
            if state.isImporting {
                HStack(spacing: 6) {
                    ProgressView()
                    Text(String(localized: "migration.importing"))
                }
            } else {
                Text(String(localized: "migration.import"))
            }
        }
        .buttonStyle(TVSettingsButtonStyle())
        .disabled(!canImport)

        Button(role: .destructive, action: onRemove) {
            Text(String(localized: "common.remove"))
                .foregroundStyle(.red)
        }
        .buttonStyle(TVSettingsButtonStyle())
        .disabled(state.isImporting)
        #else
        VStack(alignment: .leading, spacing: 12) {
            infoHeader

            credentialsFields

            if let errorMessage = state.errorMessage {
                Label(errorMessage, systemImage: "exclamationmark.triangle")
                    .font(.caption)
                    .foregroundStyle(.red)
            }

            HStack {
                Button(role: .destructive, action: onRemove) {
                    Text(String(localized: "common.remove"))
                }
                .disabled(state.isImporting)
                .foregroundStyle(.red)
                .tint(.red)

                Spacer()

                Button(action: onImport) {
                    if state.isImporting {
                        HStack(spacing: 6) {
                            ProgressView()
                                .controlSize(.small)
                            Text(String(localized: "migration.importing"))
                        }
                    } else {
                        Text(String(localized: "migration.import"))
                    }
                }
                .buttonStyle(.borderedProminent)
                .disabled(!canImport)
            }
        }
        .padding(.vertical, 8)
        #endif
    }

    @ViewBuilder
    private var credentialsFields: some View {
        #if os(tvOS)
        TVSettingsTextField(title: usernameLabel, text: $state.username)
        TVSettingsTextField(title: String(localized: "login.password"), text: $state.password, isSecure: true)
        #else
        TextField(usernameLabel, text: $state.username)
            .textContentType(.username)
            #if os(iOS)
            .textInputAutocapitalization(.never)
            #endif
            .autocorrectionDisabled()

        SecureField(String(localized: "login.password"), text: $state.password)
            .textContentType(.password)
        #endif
    }

    private var usernameLabel: String {
        switch item.instanceType {
        case .invidious:
            return String(localized: "login.email")
        default:
            return String(localized: "login.username")
        }
    }
}

// MARK: - Source Row

private struct LegacyInstanceImportRow: View {
    let item: LegacyInstanceImportItem
    let onImport: () -> Void
    let onRemove: () -> Void

    private var infoHeader: some View {
        HStack(alignment: .top, spacing: 12) {
            Image(systemName: legacyInstanceIcon(for: item.instanceType))
                .font(.title2)
                .foregroundStyle(.secondary)
                .frame(width: legacyRowIconWidth)

            VStack(alignment: .leading, spacing: 3) {
                Text(item.instanceDisplayName)
                    .font(.headline)

                // instanceDisplayName falls back to the host for unnamed
                // instances; skip the caption instead of repeating it.
                if let host = item.url.host, host != item.instanceDisplayName {
                    Text(host)
                        .font(.caption)
                        .foregroundStyle(.secondary)
                        .lineLimit(1)
                }
            }

            Spacer()
        }
    }

    var body: some View {
        #if os(tvOS)
        infoHeader
            .padding(.vertical, 8)

        Button(action: onImport) {
            Text(String(localized: "migration.import"))
        }
        .buttonStyle(TVSettingsButtonStyle())

        Button(role: .destructive, action: onRemove) {
            Text(String(localized: "common.remove"))
                .foregroundStyle(.red)
        }
        .buttonStyle(TVSettingsButtonStyle())
        #else
        VStack(alignment: .leading, spacing: 12) {
            infoHeader

            HStack {
                Button(role: .destructive, action: onRemove) {
                    Text(String(localized: "common.remove"))
                }
                .foregroundStyle(.red)
                .tint(.red)

                Spacer()

                Button(action: onImport) {
                    Text(String(localized: "migration.import"))
                }
                .buttonStyle(.borderedProminent)
            }
        }
        .padding(.vertical, 8)
        #endif
    }
}

/// tvOS renders .title2 glyphs far larger than the 28pt frame used on other platforms.
private var legacyRowIconWidth: CGFloat {
    #if os(tvOS)
    return 64
    #else
    return 28
    #endif
}

private func legacyInstanceIcon(for type: InstanceType) -> String {
    switch type {
    case .invidious:
        return "server.rack"
    case .piped:
        return "cloud"
    default:
        return "globe"
    }
}

private struct LegacyAccountRowState: Equatable {
    var username: String
    var password = ""
    var errorMessage: String?
    var isImporting = false
}

struct LegacyDataImportView: View {
    var body: some View {
        LegacyAccountsImportView()
    }
}

// MARK: - Preview

#Preview {
    NavigationStack {
        LegacyAccountsImportView()
    }
    .appEnvironment(.preview)
}
