//
//  LegacyDataMigrationService.swift
//  Yattee
//
//  Service for detecting, parsing, and importing v1 data during migration.
//

import Foundation

/// Service that handles migration of v1 Yattee data to the v2 format.
/// Detects legacy instances stored in UserDefaults and imports them into the new system.
/// Credentials are not imported - users need to sign in again after import.
@MainActor
@Observable
final class LegacyDataMigrationService {
    // MARK: - Constants

    /// UserDefaults key where v1 stored instances
    private let legacyInstancesKey = "instances"

    /// UserDefaults key where v1 stored accounts
    private let legacyAccountsKey = "accounts"

    // MARK: - Dependencies

    private let instancesManager: InstancesManager
    private let httpClient: HTTPClient

    // MARK: - State

    /// Whether an import is currently in progress
    private(set) var isImporting = false

    /// Progress of the current import (0.0 to 1.0)
    private(set) var importProgress: Double = 0.0

    // MARK: - Initialization

    init(
        instancesManager: InstancesManager,
        httpClient: HTTPClient = HTTPClient()
    ) {
        self.instancesManager = instancesManager
        self.httpClient = httpClient
    }

    // MARK: - Detection

    /// Checks if there is legacy v1 data available for migration.
    /// - Returns: true if v1 data exists and can be parsed
    func hasLegacyData() -> Bool {
        guard let items = parseLegacyData() else { return false }
        return !items.isEmpty
    }

    /// Parses legacy v1 data from UserDefaults.
    /// - Returns: Array of import items, or nil if data is corrupted or doesn't exist
    func parseLegacyData() -> [LegacyImportItem]? {
        let defaults = UserDefaults.standard

        // Check if legacy data exists
        guard defaults.object(forKey: legacyInstancesKey) != nil ||
              defaults.object(forKey: legacyAccountsKey) != nil else {
            return nil
        }

        // Parse instances only (credentials are not imported)
        let legacyInstances = parseLegacyInstances(from: defaults)

        // Build import items - one per unique instance
        var items: [LegacyImportItem] = []

        for instance in legacyInstances {
            // Skip PeerTube (not supported in migration)
            guard let instanceType = instance.instanceType,
                  instanceType != .peertube else {
                continue
            }

            guard let url = instance.url else { continue }

            let item = LegacyImportItem(
                id: UUID(),
                legacyInstanceID: instance.id,
                instanceType: instanceType,
                url: url,
                name: instance.name.isEmpty ? nil : instance.name
            )
            items.append(item)
        }

        // Return nil if no valid items were found (treat as no data)
        return items.isEmpty ? nil : items
    }

    // MARK: - Parsing Helpers

    private func parseLegacyInstances(from defaults: UserDefaults) -> [LegacyInstance] {
        // v1 used Defaults library which stores arrays of dictionaries
        guard let array = defaults.array(forKey: legacyInstancesKey) as? [[String: Any]] else {
            return []
        }

        return array.compactMap { LegacyInstance.parse(from: $0) }
    }

    // MARK: - Reachability

    /// Checks if an instance is reachable.
    /// - Parameter item: The import item to check
    /// - Returns: true if the instance responds, false otherwise
    func checkReachability(for item: LegacyImportItem) async -> Bool {
        // Build the appropriate health check endpoint based on instance type
        let endpoint: GenericEndpoint
        switch item.instanceType {
        case .invidious:
            endpoint = GenericEndpoint(path: "/api/v1/stats", timeout: 10)
        case .piped:
            endpoint = GenericEndpoint(path: "/healthcheck", timeout: 10)
        default:
            return false
        }

        do {
            _ = try await httpClient.fetchData(endpoint, baseURL: item.url)
            return true
        } catch {
            return false
        }
    }

    // MARK: - Import

    /// Imports the selected items into the v2 system.
    /// - Parameter items: The items to import (only selected items will be processed)
    /// - Returns: The result of the import operation
    func importItems(_ items: [LegacyImportItem]) async -> MigrationResult {
        isImporting = true
        importProgress = 0.0

        let selectedItems = items.filter(\.isSelected)
        var succeeded: [LegacyImportItem] = []
        var failed: [(item: LegacyImportItem, error: MigrationError)] = []
        var skippedDuplicates: [LegacyImportItem] = []

        let total = selectedItems.count

        for (index, item) in selectedItems.enumerated() {
            // Update progress
            importProgress = Double(index) / Double(max(total, 1))

            // Check for duplicates
            if isDuplicate(item) {
                skippedDuplicates.append(item)
                continue
            }

            // Perform import
            do {
                try importItem(item)
                succeeded.append(item)
            } catch let error as MigrationError {
                failed.append((item, error))
            } catch {
                failed.append((item, .unknown(error.localizedDescription)))
            }
        }

        importProgress = 1.0
        isImporting = false

        return MigrationResult(
            succeeded: succeeded,
            failed: failed,
            skippedDuplicates: skippedDuplicates
        )
    }

    /// Imports a single item into the v2 system.
    private func importItem(_ item: LegacyImportItem) throws {
        // Create the new Instance (without credentials - user needs to sign in again)
        let instance = Instance(
            id: UUID(),
            type: item.instanceType,
            url: item.url,
            name: item.name,
            isEnabled: true
        )

        // Add to instances manager
        instancesManager.add(instance)
    }

    /// Checks if an import item would be a duplicate of an existing instance.
    private func isDuplicate(_ item: LegacyImportItem) -> Bool {
        // Check if an instance with the same URL and type already exists
        for existing in instancesManager.instances {
            if existing.url.host == item.url.host && existing.type == item.instanceType {
                return true
            }
        }
        return false
    }

    // MARK: - Cleanup

    /// Deletes the legacy v1 data from UserDefaults.
    /// Call this after a successful import or when the user confirms they don't want to import.
    func deleteLegacyData() {
        let defaults = UserDefaults.standard

        // Remove legacy keys
        defaults.removeObject(forKey: legacyInstancesKey)
        defaults.removeObject(forKey: legacyAccountsKey)

        // Note: We don't delete the old Keychain items as they may be needed
        // if the user reinstalls v1 or for debugging purposes.
        // The old Keychain service name is different so there's no conflict.
    }
}
