//
//  DeepLinkHandler.swift
//  SportsTime
//
//  Handles deep link URL routing for the app
//

import Foundation
import SwiftUI

// MARK: - Deep Link Handler

@MainActor
@Observable
final class DeepLinkHandler {
    static let shared = DeepLinkHandler()

    // MARK: - State

    /// The pending poll share code from a deep link
    /// Setting to nil clears the pending state
    var pendingPollShareCode: String? {
        didSet {
            if pendingPollShareCode == nil {
                pendingPoll = nil
            }
        }
    }

    /// The loaded poll from a deep link (if successfully fetched)
    private(set) var pendingPoll: TripPoll?

    /// Whether the handler is currently loading a poll
    private(set) var isLoading = false

    /// Any error that occurred while handling a deep link
    var error: DeepLinkError?

    private init() {}

    // MARK: - URL Handling

    /// Handles an incoming URL and routes to the appropriate destination
    /// - Parameter url: The URL to handle
    /// - Returns: The parsed deep link destination, if valid
    @discardableResult
    func handleURL(_ url: URL) -> DeepLinkDestination? {
        guard let destination = parseURL(url) else { return nil }

        switch destination {
        case .poll(let shareCode):
            pendingPollShareCode = shareCode
        }

        return destination
    }

    /// Parses a URL into a deep link destination
    /// - Parameter url: The URL to parse
    /// - Returns: The parsed destination, or nil if invalid
    func parseURL(_ url: URL) -> DeepLinkDestination? {
        // Validate scheme
        guard url.scheme == "sportstime" else { return nil }

        switch url.host {
        case "poll":
            // sportstime://poll/{code}
            guard let code = url.pathComponents.dropFirst().first,
                  code.count == 6 else { return nil }
            return .poll(shareCode: code.uppercased())

        default:
            return nil
        }
    }

    /// Loads a poll by share code from CloudKit
    /// - Parameter shareCode: The 6-character share code
    func loadPoll(shareCode: String) async {
        isLoading = true
        error = nil

        do {
            let poll = try await PollService.shared.fetchPoll(byShareCode: shareCode)
            pendingPoll = poll
        } catch let pollError as PollError {
            switch pollError {
            case .pollNotFound:
                error = .pollNotFound
            case .networkUnavailable:
                error = .networkUnavailable
            default:
                error = .loadFailed(pollError)
            }
        } catch {
            self.error = .loadFailed(error)
        }

        isLoading = false
    }

    /// Clears any pending deep link state
    func clearPending() {
        pendingPollShareCode = nil
        pendingPoll = nil
        error = nil
    }
}

// MARK: - Deep Link Destination

enum DeepLinkDestination: Equatable {
    case poll(shareCode: String)
}

// MARK: - Deep Link Error

enum DeepLinkError: LocalizedError, Equatable {
    case pollNotFound
    case networkUnavailable
    case loadFailed(Error)

    var errorDescription: String? {
        switch self {
        case .pollNotFound:
            return "This poll no longer exists or the code is invalid."
        case .networkUnavailable:
            return "Unable to connect. Please check your internet connection."
        case .loadFailed(let error):
            return "Failed to load: \(error.localizedDescription)"
        }
    }

    static func == (lhs: DeepLinkError, rhs: DeepLinkError) -> Bool {
        switch (lhs, rhs) {
        case (.pollNotFound, .pollNotFound):
            return true
        case (.networkUnavailable, .networkUnavailable):
            return true
        case (.loadFailed, .loadFailed):
            return true
        default:
            return false
        }
    }
}
