import Foundation
import Observation

@MainActor
@Observable
final class SearchViewModel {

    // MARK: - Published State

    var departureAirport: Airport?
    var arrivalAirport: Airport?
    var selectedDate: Date = .now

    var departureSearchText: String = ""
    var arrivalSearchText: String = ""

    var departureSuggestions: [Airport] = []
    var arrivalSuggestions: [Airport] = []

    var departureCountrySuggestions: [Country] = []
    var arrivalCountrySuggestions: [Country] = []

    var departureRegionResult: (regionName: String, airports: [MapAirport])?
    var arrivalRegionResult: (regionName: String, airports: [MapAirport])?

    var isDepartureSearching: Bool = false
    var isArrivalSearching: Bool = false

    // MARK: - Computed

    var canSearch: Bool {
        departureAirport != nil || arrivalAirport != nil
    }

    // MARK: - Private

    private let service: FlightService
    private let database: AirportDatabase
    private var departureSearchTask: Task<Void, Never>?
    private var arrivalSearchTask: Task<Void, Never>?

    // MARK: - Init

    init(service: FlightService, database: AirportDatabase) {
        self.service = service
        self.database = database
    }

    // MARK: - Departure Search

    func departureTextChanged() {
        departureSearchTask?.cancel()
        guard departureAirport == nil else { return }

        let term = departureSearchText.trimmingCharacters(in: .whitespacesAndNewlines)
        guard !term.isEmpty else {
            departureSuggestions = []
            departureCountrySuggestions = []
            departureRegionResult = nil
            isDepartureSearching = false
            return
        }

        // Immediate local region search
        departureRegionResult = database.searchByRegion(term: term)

        departureSearchTask = Task {
            try? await Task.sleep(for: .milliseconds(300))
            guard !Task.isCancelled else { return }
            isDepartureSearching = true
            do {
                let results = try await service.searchAll(term: term)
                if !Task.isCancelled {
                    departureSuggestions = results.airports
                    departureCountrySuggestions = results.countries
                }
            } catch {
                if !Task.isCancelled {
                    departureSuggestions = []
                    departureCountrySuggestions = []
                }
            }
            if !Task.isCancelled {
                isDepartureSearching = false
            }
        }
    }

    func selectDeparture(_ airport: Airport) {
        departureAirport = airport
        departureSearchTask?.cancel()
        departureSearchText = "\(airport.iata) - \(airport.name)"
        departureSuggestions = []
        departureCountrySuggestions = []
        departureRegionResult = nil
        isDepartureSearching = false
    }

    func clearDeparture() {
        departureAirport = nil
        departureSearchTask?.cancel()
        departureSearchText = ""
        departureSuggestions = []
        departureCountrySuggestions = []
        departureRegionResult = nil
        isDepartureSearching = false
    }

    // MARK: - Arrival Search

    func arrivalTextChanged() {
        arrivalSearchTask?.cancel()
        guard arrivalAirport == nil else { return }

        let term = arrivalSearchText.trimmingCharacters(in: .whitespacesAndNewlines)
        guard !term.isEmpty else {
            arrivalSuggestions = []
            arrivalCountrySuggestions = []
            arrivalRegionResult = nil
            isArrivalSearching = false
            return
        }

        // Immediate local region search
        arrivalRegionResult = database.searchByRegion(term: term)

        arrivalSearchTask = Task {
            try? await Task.sleep(for: .milliseconds(300))
            guard !Task.isCancelled else { return }
            isArrivalSearching = true
            do {
                let results = try await service.searchAll(term: term)
                if !Task.isCancelled {
                    arrivalSuggestions = results.airports
                    arrivalCountrySuggestions = results.countries
                }
            } catch {
                if !Task.isCancelled {
                    arrivalSuggestions = []
                    arrivalCountrySuggestions = []
                }
            }
            if !Task.isCancelled {
                isArrivalSearching = false
            }
        }
    }

    func selectArrival(_ airport: Airport) {
        arrivalAirport = airport
        arrivalSearchTask?.cancel()
        arrivalSearchText = "\(airport.iata) - \(airport.name)"
        arrivalSuggestions = []
        arrivalCountrySuggestions = []
        arrivalRegionResult = nil
        isArrivalSearching = false
    }

    func clearArrival() {
        arrivalAirport = nil
        arrivalSearchTask?.cancel()
        arrivalSearchText = ""
        arrivalSuggestions = []
        arrivalCountrySuggestions = []
        arrivalRegionResult = nil
        isArrivalSearching = false
    }
}
