import SwiftUI
import UniformTypeIdentifiers
import UIKit

struct ImportDataView: View {
    enum ImportContext {
        case settings
        case onboarding
    }

    enum AccountSelection: String, CaseIterable, Identifiable {
        case existing
        case new

        var id: String { rawValue }
    }

    let importContext: ImportContext

    @EnvironmentObject private var iapService: IAPService
    @EnvironmentObject private var accountStore: AccountStore
    @EnvironmentObject private var tabSelection: TabSelectionStore
    @Environment(\.dismiss) private var dismiss

    @State private var selectedFormat: ImportService.ImportFormat = .csv
    @State private var showingImporter = false
    @State private var resultMessage: String?
    @State private var errorMessage: String?
    @State private var isImporting = false
    @State private var importProgress: Double = 0
    @State private var importStatus = "Preparing import"
    @State private var accountSelection: AccountSelection = .existing
    @State private var selectedAccountId: UUID?
    @State private var newAccountName = ""
    @State private var accountErrorMessage: String?

    // CSV column mapping flow
    @State private var pendingCSVContent: String?
    @State private var showingCSVMapping = false

    private let accountRepository = AccountRepository()

    private var availableAccounts: [Account] {
        accountStore.accounts.filter { $0.safeId != nil }
    }

    init(importContext: ImportContext = .settings) {
        self.importContext = importContext
    }

    var body: some View {
        NavigationStack {
            List {
                if shouldShowAccountSelection {
                    accountSection
                }

                Section {
                    Picker("Format", selection: $selectedFormat) {
                        Text("CSV").tag(ImportService.ImportFormat.csv)
                        Text("JSON").tag(ImportService.ImportFormat.json)
                    }
                    .pickerStyle(.segmented)
                    .disabled(isImporting)

                    Button {
                        showingImporter = true
                    } label: {
                        Label("Choose File", systemImage: "doc")
                    }
                    .disabled(isImporting)

                    Button {
                        importFromClipboard()
                    } label: {
                        Label("Paste from Clipboard", systemImage: "doc.on.clipboard")
                    }
                    .disabled(isImporting)

                    if isImporting {
                        VStack(alignment: .leading, spacing: 8) {
                            ProgressView(value: importProgress)
                            Text(importStatus)
                                .font(.caption)
                                .foregroundColor(.secondary)
                        }
                        .padding(.top, 8)
                    }
                } header: {
                    Text("Import")
                } footer: {
                    Text("Your data will be merged with existing categories and sources.")
                }

                Section {
                    if selectedFormat == .csv {
                        csvDocs
                    } else {
                        jsonDocs
                    }
                } header: {
                    Text("Format Guide")
                } footer: {
                    Text(importFooterText)
                }

                Section {
                    Button {
                        shareSampleFile()
                    } label: {
                        Label("Share Sample \(selectedFormat == .csv ? "CSV" : "JSON")", systemImage: "square.and.arrow.up")
                    }
                } footer: {
                    Text("Use this sample file to email yourself a template.")
                }
            }
            .navigationTitle("Import Data")
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    Button("Done") { dismiss() }
                        .disabled(isImporting)
                }
            }
            .fileImporter(
                isPresented: $showingImporter,
                allowedContentTypes: selectedFormat == .csv
                    ? [.commaSeparatedText, .plainText, .text]
                    : [.json, .plainText, .text],
                allowsMultipleSelection: false
            ) { result in
                handleImport(result)
            }
            .sheet(isPresented: $showingCSVMapping) {
                if let content = pendingCSVContent {
                    CSVMappingView(csvContent: content) { mapping in
                        performMappedCSVImport(content: content, mapping: mapping)
                    }
                }
            }
            .alert(
                "Import Complete",
                isPresented: Binding(
                    get: { resultMessage != nil },
                    set: { if !$0 { resultMessage = nil } }
                )
            ) {
                Button("OK") { resultMessage = nil }
            } message: {
                Text(resultMessage ?? "")
            }
            .alert(
                "Import Error",
                isPresented: Binding(
                    get: { errorMessage != nil },
                    set: { if !$0 { errorMessage = nil } }
                )
            ) {
                Button("OK") { errorMessage = nil }
            } message: {
                Text(errorMessage ?? "")
            }
            .onAppear {
                // Ensure selectedAccountId is valid and exists in availableAccounts
                let validIds = Set(availableAccounts.compactMap { $0.safeId })
                if selectedAccountId == nil || !validIds.contains(selectedAccountId!) {
                    selectedAccountId = accountStore.selectedAccount?.safeId ?? availableAccounts.first?.safeId
                }
            }
            .onChange(of: availableAccounts) { _, newAccounts in
                // Re-validate selectedAccountId when accounts change
                let validIds = Set(newAccounts.compactMap { $0.safeId })
                if let currentId = selectedAccountId, !validIds.contains(currentId) {
                    selectedAccountId = newAccounts.first?.safeId
                }
            }
            .onChange(of: accountSelection) { _, _ in
                accountErrorMessage = nil
            }
            .onChange(of: newAccountName) { _, _ in
                guard accountSelection == .new else { return }
                accountErrorMessage = validateNewAccountName()
            }
        }
        .presentationDetents([.large])
    }

    private var csvDocs: some View {
        VStack(alignment: .leading, spacing: 8) {
            Text("Headers")
                .font(.headline)
            Text("Account,Category,Source,Date,Value,Contribution,Notes")
                .font(.caption.monospaced())

            Text("Example")
                .font(.headline)
            Text("""
Personal,Stocks,Index Fund,2024-01-01,15000,12000,Long-term
,Crypto,BTC,01/15/2024 14:30,3200,,Cold storage
""")
            .font(.caption.monospaced())
            Text("Account, Contribution, and Notes are optional. Dates accept / or - and 24h/12h time.")
                .font(.caption)
                .foregroundColor(.secondary)
        }
    }

    private var jsonDocs: some View {
        VStack(alignment: .leading, spacing: 8) {
            Text("Top-level keys")
                .font(.headline)
            Text("version, currency, accounts")
                .font(.caption.monospaced())

            Text("Example")
                .font(.headline)
            Text("""
{
  "version": 2,
  "currency": "EUR",
  "accounts": [{
    "name": "Personal",
    "inputMode": "simple",
    "notificationFrequency": "monthly",
    "categories": [{
      "name": "Stocks",
      "color": "#3B82F6",
      "icon": "chart.line.uptrend.xyaxis",
      "sources": [{
        "name": "Index Fund",
        "snapshots": [{
          "date": "2024-01-01T00:00:00Z",
          "value": 15000,
          "contribution": 12000
        }]
      }]
    }]
  }]
}
""")
            .font(.caption.monospaced())
        }
    }

    private var shouldShowAccountSelection: Bool {
        // Show account selection when there are multiple accounts (Premium) or during onboarding
        iapService.isPremium && availableAccounts.count > 1 || importContext == .onboarding
    }

    private var importFooterText: String {
        if shouldShowAccountSelection {
            return iapService.isPremium
                ? "Import will be added to the selected account."
                : "Free users import into the Default account."
        }
        return "Data will be imported into your Default account."
    }

    private var accountSection: some View {
        Section {
            if iapService.isPremium {
                Picker("Account", selection: $accountSelection) {
                    Text("Existing").tag(AccountSelection.existing)
                    Text("New").tag(AccountSelection.new)
                }
                .pickerStyle(.segmented)
                .disabled(isImporting)

                if accountSelection == .existing {
                    Picker("Import into", selection: $selectedAccountId) {
                        ForEach(availableAccounts, id: \.objectID) { account in
                            Text(account.name).tag(Optional(account.safeId))
                        }
                    }
                    .disabled(isImporting)
                } else {
                    TextField("New account name", text: $newAccountName)
                        .disabled(isImporting)
                }
            } else {
                HStack {
                    Text("Account")
                    Spacer()
                    Text(selectedAccountName ?? "Personal")
                        .foregroundColor(.secondary)
                }
            }
        } header: {
            Text("Account")
        } footer: {
            if let accountErrorMessage {
                Text(accountErrorMessage)
                    .foregroundColor(.negativeRed)
            }
        }
    }

    private var selectedAccountName: String? {
        availableAccounts.first { $0.safeId == selectedAccountId }?.name
            ?? accountStore.selectedAccount?.name
            ?? availableAccounts.first?.name
    }

    private func validateNewAccountName() -> String? {
        let trimmed = newAccountName.trimmingCharacters(in: .whitespacesAndNewlines)
        guard !trimmed.isEmpty else {
            return "Enter a name for the new account."
        }
        let normalized = trimmed.lowercased()
        let exists = accountStore.accounts.contains {
            $0.name.trimmingCharacters(in: .whitespacesAndNewlines).lowercased() == normalized
        }
        return exists ? "An account with this name already exists." : nil
    }

    private func handleImport(_ result: Result<[URL], Error>) {
        do {
            let urls = try result.get()
            guard let url = urls.first else { return }
            let content = try readFileContents(from: url)
            handleImportContent(content)
        } catch {
            errorMessage = "Could not read the selected file. \(error.localizedDescription)"
        }
    }

    private func readFileContents(from url: URL) throws -> String {
        let accessing = url.startAccessingSecurityScopedResource()
        defer {
            if accessing {
                url.stopAccessingSecurityScopedResource()
            }
        }

        var coordinatorError: NSError?
        var contentError: NSError?
        var content = ""
        let coordinator = NSFileCoordinator()
        coordinator.coordinate(readingItemAt: url, options: [], error: &coordinatorError) { fileURL in
            do {
                if let isUbiquitous = try? fileURL.resourceValues(forKeys: [.isUbiquitousItemKey]).isUbiquitousItem,
                   isUbiquitous {
                    try? FileManager.default.startDownloadingUbiquitousItem(at: fileURL)
                }
                let data = try Data(contentsOf: fileURL)
                if let decoded = String(data: data, encoding: .utf8)
                    ?? String(data: data, encoding: .utf16)
                    ?? String(data: data, encoding: .isoLatin1) {
                    content = decoded
                } else {
                    throw NSError(
                        domain: "ImportDataView",
                        code: 1,
                        userInfo: [NSLocalizedDescriptionKey: "Unsupported text encoding."]
                    )
                }
            } catch {
                contentError = error as NSError
            }
        }

        if let coordinatorError {
            throw coordinatorError
        }
        if let contentError {
            throw contentError
        }
        return content
    }

    private func importFromClipboard() {
        guard let content = UIPasteboard.general.string,
              !content.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else {
            errorMessage = "Clipboard is empty."
            return
        }
        handleImportContent(content)
    }

    private func resolvedAccountName() -> String {
        let useAccountSelection = shouldShowAccountSelection && iapService.isPremium
        var defaultAccountName = accountStore.accounts.first(where: { $0.isDefaultAccount })?.name
            ?? accountStore.selectedAccount?.name
            ?? accountStore.accounts.first?.name
            ?? Account.defaultAccountName

        if useAccountSelection {
            if accountSelection == .new {
                let trimmed = newAccountName.trimmingCharacters(in: .whitespacesAndNewlines)
                if !trimmed.isEmpty {
                    let currency = AppSettings.getOrCreate(in: CoreDataStack.shared.viewContext).currency
                    let account = accountRepository.createAccount(
                        name: trimmed,
                        currency: currency,
                        inputMode: .simple,
                        notificationFrequency: .monthly,
                        customFrequencyMonths: 1
                    )
                    defaultAccountName = account.name
                }
            } else {
                defaultAccountName = selectedAccountName ?? defaultAccountName
            }
        }
        return defaultAccountName
    }

    private func handleImportContent(_ content: String) {
        let useAccountSelection = shouldShowAccountSelection && iapService.isPremium

        if useAccountSelection && accountSelection == .new {
            accountErrorMessage = validateNewAccountName()
            guard accountErrorMessage == nil else { return }
        }

        // CSV → show column mapping sheet first
        if selectedFormat == .csv {
            pendingCSVContent = content
            showingCSVMapping = true
            return
        }

        // JSON → import directly
        runImport(content: content, format: .json, defaultAccountName: resolvedAccountName())
    }

    private func performMappedCSVImport(content: String, mapping: ImportService.CSVMappingConfig) {
        let defaultAccountName = resolvedAccountName()
        isImporting = true
        importProgress = 0
        importStatus = "Parsing file"

        Task {
            let importResult = await ImportService.shared.importCSVWithMappingAsync(
                content: content,
                mapping: mapping,
                defaultAccountName: defaultAccountName
            ) { progress in
                importProgress = progress.fraction
                importStatus = progress.message
            }
            finishImport(importResult)
        }
    }

    private func runImport(content: String, format: ImportService.ImportFormat, defaultAccountName: String) {
        isImporting = true
        importProgress = 0
        importStatus = "Parsing file"

        Task {
            let importResult = await ImportService.shared.importDataAsync(
                content: content,
                format: format,
                allowMultipleAccounts: false,
                defaultAccountName: defaultAccountName
            ) { progress in
                importProgress = progress.fraction
                importStatus = progress.message
            }
            finishImport(importResult)
        }
    }

    private func finishImport(_ importResult: ImportService.ImportResult) {
        isImporting = false

        if importResult.errors.isEmpty {
            var message = "Imported \(importResult.sourcesCreated) sources and \(importResult.snapshotsCreated) snapshots."
            if importResult.snapshotsUpdated > 0 {
                message += " Updated \(importResult.snapshotsUpdated) existing snapshots."
            }
            resultMessage = message
            tabSelection.selectedTab = 0
            dismiss()
        } else {
            errorMessage = importResult.errors.joined(separator: "\n")
        }
    }

    private func shareSampleFile() {
        if selectedFormat == .csv {
            ShareService.shared.shareTextFile(
                content: ImportService.sampleCSV(),
                fileName: "investment_tracker_sample.csv"
            )
        } else {
            ShareService.shared.shareTextFile(
                content: ImportService.sampleJSON(),
                fileName: "investment_tracker_sample.json"
            )
        }
    }
}

#Preview {
    ImportDataView()
        .environmentObject(IAPService())
        .environmentObject(AccountStore(iapService: IAPService()))
}
