import SwiftUI
import UniformTypeIdentifiers
import CoreData

struct SettingsView: View {
    @State private var showingImportPicker = false
    @State private var showingImportResult = false
    @State private var importResultMessage = ""
    @State private var importedCount = 0
    @State private var isImporting = false
    @EnvironmentObject var linkViewModel: LinkViewModel

    var body: some View {
        NavigationView {
            List {
                Section {
                    NavigationLink(destination: LanguageSettingsView()) {
                        Label("change_language", systemImage: "globe")
                    }

                    Button(action: {
                        showingImportPicker = true
                    }) {
                        HStack {
                            Label("import_links", systemImage: "square.and.arrow.down")
                                .foregroundColor(.primary)
                            Spacer()
                            if isImporting {
                                ProgressView()
                                    .scaleEffect(0.8)
                            }
                        }
                    }
                    .disabled(isImporting)
                }
            }
            .navigationTitle("settings")
            .fileImporter(
                isPresented: $showingImportPicker,
                allowedContentTypes: [UTType.json],
                allowsMultipleSelection: false
            ) { result in
                handleImportResult(result)
            }
            .alert("import_result", isPresented: $showingImportResult) {
                Button("ok") { }
            } message: {
                Text(importResultMessage)
            }
        }
    }

    private func handleImportResult(_ result: Result<[URL], Error>) {
        switch result {
        case .success(let urls):
            guard let url = urls.first else { return }
            importLinks(from: url)
        case .failure(let error):
            importResultMessage = String(format: NSLocalizedString("import_error", comment: ""), error.localizedDescription)
            showingImportResult = true
        }
    }

    private func importLinks(from url: URL) {
        isImporting = true

        guard url.startAccessingSecurityScopedResource() else {
            importResultMessage = NSLocalizedString("file_access_error", comment: "")
            showingImportResult = true
            isImporting = false
            return
        }

        defer { url.stopAccessingSecurityScopedResource() }

        do {
            let data = try Data(contentsOf: url)

            let context = PersistenceController.shared.container.viewContext
            var importedCount = 0
            var skippedCount = 0
            var failedEntries: [String] = []

            // Helper to generate slug similar to backend slugify
            func generateSlug(_ raw: String) -> String {
                let base = raw
                    .lowercased()
                    .trimmingCharacters(in: .whitespacesAndNewlines)
                    .replacingOccurrences(of: " ", with: "-")
                    .replacingOccurrences(of: "[^a-z0-9-]", with: "", options: .regularExpression)
                return base
            }

            // Fetch or create tag ensuring unique slug
            func fetchOrCreateTag(named name: String) throws -> Tag {
                let trimmed = name.trimmingCharacters(in: .whitespacesAndNewlines)
                if trimmed.isEmpty { throw NSError(domain: "Import", code: 10, userInfo: [NSLocalizedDescriptionKey: "Empty tag name"]) }

                // Case-insensitive fetch
                let request: NSFetchRequest<Tag> = Tag.fetchRequest()
                request.predicate = NSPredicate(format: "name ==[c] %@", trimmed)
                request.fetchLimit = 1
                if let existing = try context.fetch(request).first { return existing }

                // Create new tag with unique slug
                let tag = Tag(context: context)
                tag.name = trimmed
                var slug = generateSlug(trimmed)
                if slug.isEmpty { slug = UUID().uuidString.prefix(8).lowercased() }

                // Ensure slug uniqueness
                var uniqueSlug = slug
                var index = 1
                while true {
                    let slugRequest: NSFetchRequest<Tag> = Tag.fetchRequest()
                    slugRequest.predicate = NSPredicate(format: "slug == %@", uniqueSlug)
                    slugRequest.fetchLimit = 1
                    if try context.count(for: slugRequest) == 0 { break }
                    uniqueSlug = "\(slug)-\(index)"
                    index += 1
                }
                tag.slug = uniqueSlug
                tag.createdAt = Date()
                return tag
            }

            // First try to parse the entire JSON as LinkData array
            do {
                let linkDataArray = try JSONDecoder().decode([LinkData].self, from: data)

                // If successful, process normally
                for linkData in linkDataArray {
                    do {
                        // Check if link with same alias already exists
                        let fetchRequest: NSFetchRequest<Link> = Link.fetchRequest()
                        fetchRequest.predicate = NSPredicate(format: "alias == %@", linkData.alias.lowercased())

                        if try context.count(for: fetchRequest) == 0 {
                            // Create new link
                            let link = Link(context: context)
                            link.alias = linkData.alias.lowercased()
                            link.originalURL = linkData.originalUrl
                            link.linkType = linkData.linkType ?? "LINK"
                            link.text = linkData.text
                            link.createdAt = linkData.createdAt ?? Date()
                            link.updatedAt = linkData.updatedAt ?? Date()
                            link.clickCount = 0

                            // Handle tags if present
                            if let tagNames = linkData.tags {
                                for tagName in tagNames {
                                    do {
                                        let tag = try fetchOrCreateTag(named: tagName)
                                        link.addToTags(tag)
                                    } catch {
                                        print("⚠️ Skipped tag '\(tagName)': \(error.localizedDescription)")
                                    }
                                }
                            }

                            importedCount += 1
                        } else {
                            skippedCount += 1
                        }
                    } catch {
                        // If individual processing fails, add to failed entries
                        failedEntries.append(linkData.alias)
                        print("Failed to process entry '\(linkData.alias)': \(error.localizedDescription)")
                    }
                }

            } catch {
                // If parsing entire array fails, try individual entry parsing
                print("Failed to parse as LinkData array, trying individual parsing: \(error)")

                guard let jsonArray = try JSONSerialization.jsonObject(with: data, options: []) as? [[String: Any]] else {
                    throw NSError(domain: "ImportError", code: 1, userInfo: [NSLocalizedDescriptionKey: "Invalid JSON format - not an array"])
                }

                for (index, jsonEntry) in jsonArray.enumerated() {
                    do {
                        // Try to parse individual entry
                        let entryData = try JSONSerialization.data(withJSONObject: jsonEntry, options: [])
                        let linkData = try JSONDecoder().decode(LinkData.self, from: entryData)

                        // Check if link with same alias already exists
                        let fetchRequest: NSFetchRequest<Link> = Link.fetchRequest()
                        fetchRequest.predicate = NSPredicate(format: "alias == %@", linkData.alias.lowercased())

                        if try context.count(for: fetchRequest) == 0 {
                            // Create new link
                            let link = Link(context: context)
                            link.alias = linkData.alias.lowercased()
                            link.originalURL = linkData.originalUrl
                            link.linkType = linkData.linkType ?? "LINK"
                            link.text = linkData.text
                            link.createdAt = linkData.createdAt ?? Date()
                            link.updatedAt = linkData.updatedAt ?? Date()
                            link.clickCount = 0

                            // Handle tags if present
                            if let tagNames = linkData.tags {
                                for tagName in tagNames {
                                    do {
                                        let tag = try fetchOrCreateTag(named: tagName)
                                        link.addToTags(tag)
                                    } catch {
                                        print("⚠️ Skipped tag '\(tagName)': \(error.localizedDescription)")
                                    }
                                }
                            }

                            importedCount += 1
                        } else {
                            skippedCount += 1
                        }
                    } catch {
                        // If individual entry fails, collect the alias and continue
                        let alias = jsonEntry["alias"] as? String ?? "Entry #\(index + 1)"
                        failedEntries.append(alias)
                        print("Failed to import entry '\(alias)': \(error.localizedDescription)")
                    }
                }
            }

            do {
                try context.save()
            } catch {
                let nsError = error as NSError
                if let detailed = nsError.userInfo[NSDetailedErrorsKey] as? [NSError] {
                    for d in detailed { print("❌ Save detail: \(d), userInfo: \(d.userInfo)") }
                } else {
                    print("❌ Save error: \(nsError), userInfo: \(nsError.userInfo)")
                }
                throw nsError
            }

            // Refresh the link view model
            linkViewModel.fetchLinks()

            self.importedCount = importedCount

            // Build result message
            var resultParts: [String] = []

            if importedCount > 0 {
                resultParts.append(String(format: NSLocalizedString("import_success", comment: ""), importedCount))
            }

            if skippedCount > 0 {
                resultParts.append(String(format: NSLocalizedString("import_skipped", comment: ""), skippedCount))
            }

            if !failedEntries.isEmpty {
                resultParts.append(String(format: NSLocalizedString("import_failed", comment: ""), failedEntries.count))
                resultParts.append("Failed entries: \(failedEntries.joined(separator: ", "))")
            }

            importResultMessage = resultParts.joined(separator: "\n")
            showingImportResult = true

        } catch {
            importResultMessage = String(format: NSLocalizedString("import_parse_error", comment: ""), error.localizedDescription)
            showingImportResult = true
        }

        isImporting = false
    }
}

struct LanguageSettingsView: View {
    @AppStorage("selectedLanguage") private var selectedLanguage = "system"
    @State private var showingRestartAlert = false

    private let languages = [
        ("system", "system_language", "🌐"),
        ("en", "english", "🇺🇸"),
        ("zh-Hans", "chinese_simplified", "🇨🇳")
    ]

    var body: some View {
        List {
            ForEach(languages, id: \.0) { code, nameKey, flag in
                Button(action: {
                    let previousLanguage = selectedLanguage
                    selectedLanguage = code
                    setLanguage(code)

                    // Show restart alert if language actually changed
                    if previousLanguage != code {
                        showingRestartAlert = true
                    }
                }) {
                    HStack {
                        Text(flag)
                        Text(NSLocalizedString(nameKey, comment: ""))
                            .foregroundColor(.primary)
                        Spacer()
                        if selectedLanguage == code {
                            Image(systemName: "checkmark")
                                .foregroundColor(.accentColor)
                        }
                    }
                }
            }
        }
        .navigationTitle("change_language")
        .navigationBarTitleDisplayMode(.inline)
        .alert("language_changed", isPresented: $showingRestartAlert) {
            Button("ok") { }
        } message: {
            Text("restart_app_message")
        }
    }

    private func setLanguage(_ languageCode: String) {
        if languageCode == "system" {
            UserDefaults.standard.removeObject(forKey: "AppleLanguages")
        } else {
            UserDefaults.standard.set([languageCode], forKey: "AppleLanguages")
        }

        // Note: Language change will take effect after app restart
        // You could show an alert informing the user about this
    }
}

// Data structure for importing links
struct LinkData: Codable {
    let alias: String
    let originalUrl: String?
    let linkType: String?
    let text: String?
    let createdAt: Date?
    let updatedAt: Date?
    let tags: [String]?

    enum CodingKeys: String, CodingKey {
        case alias
        case originalUrl = "original_url"
        case linkType = "link_type"
        case text
        case createdAt = "created_at"
        case updatedAt = "updated_at"
        case tags
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        alias = try container.decode(String.self, forKey: .alias)
        originalUrl = try container.decodeIfPresent(String.self, forKey: .originalUrl)
        linkType = try container.decodeIfPresent(String.self, forKey: .linkType)
        text = try container.decodeIfPresent(String.self, forKey: .text)
        tags = try container.decodeIfPresent([String].self, forKey: .tags)

        // Handle date parsing with multiple formatters
        if let createdAtString = try container.decodeIfPresent(String.self, forKey: .createdAt) {
            createdAt = Self.parseDate(from: createdAtString)
        } else {
            createdAt = nil
        }

        if let updatedAtString = try container.decodeIfPresent(String.self, forKey: .updatedAt) {
            updatedAt = Self.parseDate(from: updatedAtString)
        } else {
            updatedAt = nil
        }
    }

    private static func parseDate(from dateString: String) -> Date? {
        // Try ISO8601 formatters first
        let iso8601Formatter1 = ISO8601DateFormatter()

        let iso8601Formatter2 = ISO8601DateFormatter()
        iso8601Formatter2.formatOptions = [.withInternetDateTime, .withFractionalSeconds]

        let iso8601Formatters = [iso8601Formatter1, iso8601Formatter2]

        for formatter in iso8601Formatters {
            if let date = formatter.date(from: dateString) {
                return date
            }
        }

        // Try custom DateFormatter patterns
        let dateFormatter1 = DateFormatter()
        dateFormatter1.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSZZZZZ"

        let dateFormatter2 = DateFormatter()
        dateFormatter2.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"

        let dateFormatter3 = DateFormatter()
        dateFormatter3.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"

        let dateFormatters = [dateFormatter1, dateFormatter2, dateFormatter3]

        for formatter in dateFormatters {
            if let date = formatter.date(from: dateString) {
                return date
            }
        }

        return nil
    }
}

#Preview {
    SettingsView()
        .environmentObject(LinkViewModel())
}
