import Foundation
import AuthenticationServices
import UIKit

/// Handles Sign in with Apple authentication flow
@MainActor
class AppleSignInManager: NSObject, ObservableObject {
    // MARK: - Published Properties
    @Published var isProcessing: Bool = false
    @Published var error: Error?

    // MARK: - Completion Handler
    private var completionHandler: ((Result<AppleSignInCredential, Error>) -> Void)?

    // MARK: - Public Methods

    /// Initiates the Sign in with Apple flow
    /// - Parameter completion: Callback with either credentials or error
    func signIn(completion: @escaping (Result<AppleSignInCredential, Error>) -> Void) {
        self.completionHandler = completion
        self.error = nil
        self.isProcessing = true

        let request = ASAuthorizationAppleIDProvider().createRequest()
        request.requestedScopes = [.fullName, .email]

        let controller = ASAuthorizationController(authorizationRequests: [request])
        controller.delegate = self
        controller.presentationContextProvider = self
        controller.performRequests()
    }
}

// MARK: - ASAuthorizationControllerDelegate

extension AppleSignInManager: ASAuthorizationControllerDelegate {
    nonisolated func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
        Task { @MainActor in
            isProcessing = false

            guard let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential else {
                let error = AppleSignInError.invalidCredential
                self.error = error
                completionHandler?(.failure(error))
                return
            }

            // Get the identity token as a string
            guard let identityTokenData = appleIDCredential.identityToken,
                  let identityToken = String(data: identityTokenData, encoding: .utf8) else {
                let error = AppleSignInError.missingIdentityToken
                self.error = error
                completionHandler?(.failure(error))
                return
            }

            // Extract user info (only available on first sign in)
            let email = appleIDCredential.email
            let firstName = appleIDCredential.fullName?.givenName
            let lastName = appleIDCredential.fullName?.familyName
            let userIdentifier = appleIDCredential.user

            let credential = AppleSignInCredential(
                identityToken: identityToken,
                userIdentifier: userIdentifier,
                email: email,
                firstName: firstName,
                lastName: lastName
            )

            completionHandler?(.success(credential))
        }
    }

    nonisolated func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
        Task { @MainActor in
            isProcessing = false

            // Check if user cancelled
            if let authError = error as? ASAuthorizationError {
                switch authError.code {
                case .canceled:
                    // User cancelled, don't treat as error
                    self.error = AppleSignInError.userCancelled
                    completionHandler?(.failure(AppleSignInError.userCancelled))
                    return
                case .failed:
                    self.error = AppleSignInError.authorizationFailed
                    completionHandler?(.failure(AppleSignInError.authorizationFailed))
                    return
                case .invalidResponse:
                    self.error = AppleSignInError.invalidResponse
                    completionHandler?(.failure(AppleSignInError.invalidResponse))
                    return
                case .notHandled:
                    self.error = AppleSignInError.notHandled
                    completionHandler?(.failure(AppleSignInError.notHandled))
                    return
                case .notInteractive:
                    self.error = AppleSignInError.notInteractive
                    completionHandler?(.failure(AppleSignInError.notInteractive))
                    return
                default:
                    self.error = AppleSignInError.authorizationFailed
                    completionHandler?(.failure(AppleSignInError.authorizationFailed))
                    return
                }
            }

            self.error = error
            completionHandler?(.failure(error))
        }
    }
}

// MARK: - ASAuthorizationControllerPresentationContextProviding

extension AppleSignInManager: ASAuthorizationControllerPresentationContextProviding {
    nonisolated func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor {
        // This method is always called on the main thread by Apple's framework.
        // Use DispatchQueue.main.sync as a safe bridge instead of assumeIsolated.
        DispatchQueue.main.sync {
            // Get the key window for presentation
            guard let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
                  let window = scene.windows.first(where: { $0.isKeyWindow }) else {
                // Fallback to first window
                return UIApplication.shared.connectedScenes
                    .compactMap { $0 as? UIWindowScene }
                    .flatMap { $0.windows }
                    .first ?? ASPresentationAnchor()
            }
            return window
        }
    }
}

// MARK: - Supporting Types

/// Credentials returned from successful Apple Sign In
struct AppleSignInCredential {
    let identityToken: String
    let userIdentifier: String
    let email: String?
    let firstName: String?
    let lastName: String?
}

/// Custom errors for Apple Sign In
enum AppleSignInError: LocalizedError {
    case invalidCredential
    case missingIdentityToken
    case userCancelled
    case authorizationFailed
    case invalidResponse
    case notHandled
    case notInteractive
    case serverError(String)

    var errorDescription: String? {
        switch self {
        case .invalidCredential:
            return "Invalid Apple ID credential"
        case .missingIdentityToken:
            return "Missing identity token from Apple"
        case .userCancelled:
            return nil // Don't show error for user cancellation
        case .authorizationFailed:
            return "Apple Sign In authorization failed"
        case .invalidResponse:
            return "Invalid response from Apple"
        case .notHandled:
            return "Apple Sign In request was not handled"
        case .notInteractive:
            return "Apple Sign In requires user interaction"
        case .serverError(let message):
            return message
        }
    }

    var isCancellation: Bool {
        if case .userCancelled = self {
            return true
        }
        return false
    }
}
