// composables/useFlightStats.ts
import { computed, Ref, watch } from 'vue'
import type { Airport, Flight } from '@/Types/types'

const DAYS   = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
const MONTHS = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']

// ── Date part cache ───────────────────────────────────────────────────────────

const dateCache = new Map<number, { year: number; month: number; day: number }>()

function getDateParts(f: Flight): { year: number; month: number; day: number } {
    if (dateCache.has(f.id)) return dateCache.get(f.id)!

    const tz   = f.departure_airport.timezone
    const date = new Date(f.departure_date)
    const fmt  = (opts: Intl.DateTimeFormatOptions) =>
        new Intl.DateTimeFormat('en', { timeZone: tz, ...opts }).format(date)

    const localDay = fmt({ weekday: 'long' })
    const dayIdx   = DAYS.indexOf(localDay)

    const parts = {
        year:  Number(fmt({ year: 'numeric' })),
        month: Number(fmt({ month: 'numeric' })) - 1,
        day:   dayIdx === -1 ? 0 : dayIdx,
    }

    dateCache.set(f.id, parts)
    return parts
}

// ── Per year / month / day ────────────────────────────────────────────────────

export function getFlightsPerYear(flights: Flight[], upcomingFlights: Flight[]) {
    const allFlights = [...flights, ...upcomingFlights]

    const allYears = new Set(allFlights.map(f => getDateParts(f).year))
    const sorted   = [...allYears].sort((a, b) => a - b)

    let min = sorted[0]
    let max = sorted[sorted.length - 1]
    while (max - min + 1 < 5) {
        min--
        if (max - min + 1 < 5) max++
    }

    const years = Array.from({ length: max - min + 1 }, (_, i) => min + i)
    const countByYear = (list: Flight[]) =>
        years.map(year => list.filter(f => getDateParts(f).year === year).length)

    const result = {
        years,
        series: [
            { name: 'Flown',    data: countByYear(flights) },
            { name: 'Upcoming', data: countByYear(upcomingFlights) },
        ],
    }
    return result
}

export function getFlightsPerMonth(flights: Flight[], upcomingFlights: Flight[]) {
    const countByMonth = (list: Flight[]) =>
        MONTHS.map((_, i) => list.filter(f => getDateParts(f).month === i).length)

    const result = {
        months: MONTHS,
        series: [
            { name: 'Flown',    data: countByMonth(flights) },
            { name: 'Upcoming', data: countByMonth(upcomingFlights) },
        ],
    }
    return result
}

export function getFlightsPerDay(flights: Flight[], upcomingFlights: Flight[]) {
    const countByDay = (list: Flight[]) =>
        DAYS.map((_, i) => list.filter(f => getDateParts(f).day === i).length)

    const result = {
        days: DAYS,
        series: [
            { name: 'Flown',    data: countByDay(flights) },
            { name: 'Upcoming', data: countByDay(upcomingFlights) },
        ],
    }
    return result
}

// ── Grouping helpers ──────────────────────────────────────────────────────────

function groupByName(flights: Flight[], accessor: (f: Flight) => string) {
    const counts = new Map<string, number>()
    flights.forEach(f => {
        const key = accessor(f) ?? 'Unknown'
        counts.set(key, (counts.get(key) ?? 0) + 1)
    })
    const sorted = [...counts.entries()].sort((a, b) => b[1] - a[1])
    return {
        labels: sorted.map(([name]) => name),
        series: sorted.map(([, count]) => count),
    }
}

export function getFlightReasons(flights: Flight[]) {
    const result = groupByName(flights, f => f.flight_reason?.name ?? 'Unknown')
    return result
}

export function getFlightClasses(flights: Flight[]) {
    const result = groupByName(flights, f => f.flight_class?.name ?? 'Unknown')
    return result
}

export function getSeatTypes(flights: Flight[]) {
    const result = groupByName(flights, f => f.seat_type?.name ?? 'Unknown')
    return result
}

// ── Countries ─────────────────────────────────────────────────────────────────

function countCountries(flights: Flight[]) {
    const counts = new Map<string, { count: number; code: string }>()
    flights.forEach(f => {
        const dep = f.departure_airport?.region?.country
        const arr = f.arrival_airport?.region?.country

        if (dep?.name) {
            const existing = counts.get(dep.name) ?? { count: 0, code: dep.code }
            existing.count++
            counts.set(dep.name, existing)
        }
        if (arr?.name && arr.name !== dep?.name) {
            const existing = counts.get(arr.name) ?? { count: 0, code: arr.code }
            existing.count++
            counts.set(arr.name, existing)
        }
    })
    return counts
}

export function getCountries(flights: Flight[], upcomingFlights: Flight[]) {
    const past     = countCountries(flights)
    const upcoming = countCountries(upcomingFlights)
    const allNames = new Set([...past.keys(), ...upcoming.keys()])

    const sorted = [...allNames]
        .map(name => ({
            name,
            code:     (past.get(name) ?? upcoming.get(name))!.code,
            past:     past.get(name)?.count ?? 0,
            upcoming: upcoming.get(name)?.count ?? 0,
        }))
        .sort((a, b) => (b.past + b.upcoming) - (a.past + a.upcoming))

    const result = {
        countries: sorted,
        series: [
            { name: 'Flights',  data: sorted.map(s => s.past) },
            { name: 'Upcoming', data: sorted.map(s => s.upcoming) },
        ],
    }
    return result
}

// ── Continents ────────────────────────────────────────────────────────────────

export function getContinents(flights: Flight[]) {
    const counts = new Map<string, number>()
    flights.forEach(f => {
        const continents = new Set<string>()
        const dep = f.departure_airport.region?.continent?.name
        const arr = f.arrival_airport.region?.continent?.name
        if (dep) continents.add(dep)
        if (arr) continents.add(arr)
        continents.forEach(c => counts.set(c, (counts.get(c) ?? 0) + 1))
    })
    const sorted = [...counts.entries()].sort((a, b) => b[1] - a[1])
    const result = {
        labels: sorted.map(([name]) => name),
        series: sorted.map(([, count]) => count),
    }
    return result
}

// ── Airlines ──────────────────────────────────────────────────────────────────

function countAirlines(flights: Flight[]) {
    const counts = new Map<string, { count: number; id: number, logo_url: string }>()
    flights.forEach(f => {
        const airline = f.airline
        if (!airline?.name) return
        const existing = counts.get(airline.name) ?? { count: 0, id: airline.id, logo_url: airline.logo_url }
        existing.count++
        counts.set(airline.name, existing)
    })
    return counts
}

export function getTopAirlines(flights: Flight[], upcomingFlights: Flight[]) {
    const past     = countAirlines(flights)
    const upcoming = countAirlines(upcomingFlights)
    const allNames = new Set([...past.keys(), ...upcoming.keys()])

    const sorted = [...allNames]
        .map(name => ({
            name,
            id:       (past.get(name) ?? upcoming.get(name))!.id,
            past:     past.get(name)?.count ?? 0,
            upcoming: upcoming.get(name)?.count ?? 0,
            logo_url:  (past.get(name) ?? upcoming.get(name))!.logo_url,
        }))
        .sort((a, b) => (b.past + b.upcoming) - (a.past + a.upcoming))

    const result = {
        airlines: sorted,
        series: [
            { name: 'Flights',  data: sorted.map(s => s.past) },
            { name: 'Upcoming', data: sorted.map(s => s.upcoming) },
        ],
    }
    return result
}

// ── Airports ──────────────────────────────────────────────────────────────────

interface AirportItem {
    label: string
    fullName: string
    departures: number
    arrivals: number
    upcoming: number
}

function airportLabel(airport: Airport | null | undefined): string | null {
    if (!airport) return null
    return airport.iata_code ?? airport.icao_code ?? airport.name ?? null
}

export function getTopAirports(flights: Flight[], upcomingFlights: Flight[]) {
    const map   = new Map<string, AirportItem>()
    const empty = (): AirportItem => ({ departures: 0, arrivals: 0, upcoming: 0, label: '', fullName: '' })

    flights.forEach(f => {
        const depLabel = airportLabel(f.departure_airport)
        const arrLabel = airportLabel(f.arrival_airport)

        if (depLabel) {
            const e = map.get(depLabel) ?? empty()
            e.departures++
            e.label    = depLabel
            e.fullName = f.departure_airport?.name ?? depLabel
            map.set(depLabel, e)
        }
        if (arrLabel) {
            const e = map.get(arrLabel) ?? empty()
            e.arrivals++
            e.label    = arrLabel
            e.fullName = f.arrival_airport?.name ?? arrLabel
            map.set(arrLabel, e)
        }
    })

    upcomingFlights.forEach(f => {
        const depLabel = airportLabel(f.departure_airport)
        const arrLabel = airportLabel(f.arrival_airport)

        if (depLabel) {
            const e = map.get(depLabel) ?? empty()
            e.upcoming++
            e.label    = depLabel
            e.fullName = f.departure_airport?.name ?? depLabel
            map.set(depLabel, e)
        }
        if (arrLabel) {
            const e = map.get(arrLabel) ?? empty()
            e.upcoming++
            e.label    = arrLabel
            e.fullName = f.arrival_airport?.name ?? arrLabel
            map.set(arrLabel, e)
        }
    })

    const sorted = [...map.values()]
        .sort((a, b) =>
            (b.departures + b.arrivals + b.upcoming) - (a.departures + a.arrivals + a.upcoming)
        )

    const result = {
        airports: sorted,
        series: [
            { name: 'Departures', data: sorted.map(s => s.departures) },
            { name: 'Arrivals',   data: sorted.map(s => s.arrivals) },
            { name: 'Upcoming',   data: sorted.map(s => s.upcoming) },
        ],
    }
    return result
}

// ── Aircraft ──────────────────────────────────────────────────────────────────

interface AircraftItem {
    label: string
    id: number
    past: number
    upcoming: number
    designator: string
}

export function getTopAircraft(flights: Flight[], upcomingFlights: Flight[]) {

    function countAircraft(list: Flight[]) {
        const counts = new Map<string, { count: number; id: number; displayName: string; designator: string }>()
        list.forEach(f => {
            const aircraft = f.aircraft
            if (!aircraft?.designator) return
            const existing = counts.get(aircraft.designator) ?? { count: 0, id: aircraft.id, displayName: aircraft.display_name_short, designator: aircraft.designator }
            existing.count++
            counts.set(aircraft.designator, existing)
        })
        return counts
    }

    const past     = countAircraft(flights)
    const upcoming = countAircraft(upcomingFlights)
    const allNames = new Set([...past.keys(), ...upcoming.keys()])

    const sorted: AircraftItem[] = [...allNames]
        .map(name => ({
            label:    (past.get(name) ?? upcoming.get(name))!.displayName,
            designator: (past.get(name) ?? upcoming.get(name))!.designator,
            id:       (past.get(name) ?? upcoming.get(name))!.id,
            past:     past.get(name)?.count ?? 0,
            upcoming: upcoming.get(name)?.count ?? 0,
        }))
        .sort((a, b) => (b.past + b.upcoming) - (a.past + a.upcoming))

    const result = {
        aircraft: sorted,
        series: [
            { name: 'Flights',  data: sorted.map(s => s.past) },
            { name: 'Upcoming', data: sorted.map(s => s.upcoming) },
        ],
    }
    return result
}

// ── Routes ────────────────────────────────────────────────────────────────────

interface RouteItem {
    label: string
    depLabel: string
    arrLabel: string
    past: number
    upcoming: number
}

export function getTopRoutes(flights: Flight[], upcomingFlights: Flight[]) {

    function countRoutes(list: Flight[]) {
        const counts = new Map<string, { count: number; depLabel: string; arrLabel: string }>()
        list.forEach(f => {
            const dep = airportLabel(f.departure_airport)
            const arr = airportLabel(f.arrival_airport)
            if (!dep || !arr) return
            const key = `${dep}-${arr}`
            const existing = counts.get(key) ?? { count: 0, depLabel: dep, arrLabel: arr }
            existing.count++
            counts.set(key, existing)
        })
        return counts
    }

    const past     = countRoutes(flights)
    const upcoming = countRoutes(upcomingFlights)
    const allKeys  = new Set([...past.keys(), ...upcoming.keys()])

    const sorted: RouteItem[] = [...allKeys]
        .map(key => {
            const meta = (past.get(key) ?? upcoming.get(key))!
            return {
                label:    key,
                depLabel: meta.depLabel,
                arrLabel: meta.arrLabel,
                past:     past.get(key)?.count ?? 0,
                upcoming: upcoming.get(key)?.count ?? 0,
            }
        })
        .sort((a, b) => (b.past + b.upcoming) - (a.past + a.upcoming))

    const result = {
        routes: sorted,
        series: [
            { name: 'Flights',  data: sorted.map(s => s.past) },
            { name: 'Upcoming', data: sorted.map(s => s.upcoming) },
        ],
    }
    return result
}

// ── Flight types ──────────────────────────────────────────────────────────────

export function getFlightTypes(flights: Flight[]) {
    const counts = { International: 0, Domestic: 0 }
    flights.forEach(f => {
        const dep = f.departure_airport.region?.country?.id
        const arr = f.arrival_airport.region?.country?.id
        if (dep && arr) {
            dep === arr ? counts.Domestic++ : counts.International++
        }
    })
    const sorted = Object.entries(counts).filter(([, count]) => count > 0)
    const result = {
        labels: sorted.map(([name]) => name),
        series: sorted.map(([, count]) => count),
    }
    return result
}

// ── Composable ────────────────────────────────────────────────────────────────

export type FlightStats = ReturnType<typeof useFlightStats>

export function useFlightStats(flights: Ref<Flight[]>) {
    const now = new Date()

    watch(flights, (list) => {
        list.forEach(f => getDateParts(f))
    }, { immediate: true })

    const pastFlights = computed(() => {
        const result = flights.value.filter(f => new Date(f.departure_date) <= now)
        return result
    })

    const upcomingFlights = computed(() => {
        const result = flights.value.filter(f => new Date(f.departure_date) > now)
        return result
    })

    const allFlights = computed(() => flights.value)

    const perYear     = computed(() => getFlightsPerYear(pastFlights.value, upcomingFlights.value))
    const perMonth    = computed(() => getFlightsPerMonth(pastFlights.value, upcomingFlights.value))
    const perDay      = computed(() => getFlightsPerDay(pastFlights.value, upcomingFlights.value))
    const reasons     = computed(() => getFlightReasons(allFlights.value))
    const classes     = computed(() => getFlightClasses(allFlights.value))
    const seatTypes   = computed(() => getSeatTypes(allFlights.value))
    const countries   = computed(() => getCountries(pastFlights.value, upcomingFlights.value))
    const continents  = computed(() => getContinents(allFlights.value))
    const topAirlines = computed(() => getTopAirlines(pastFlights.value, upcomingFlights.value))
    const topAirports = computed(() => getTopAirports(pastFlights.value, upcomingFlights.value))
    const topAircraft = computed(() => getTopAircraft(pastFlights.value, upcomingFlights.value))
    const topRoutes   = computed(() => getTopRoutes(pastFlights.value, upcomingFlights.value))
    const flightTypes = computed(() => getFlightTypes(allFlights.value))

    return {
        pastFlights,
        upcomingFlights,
        perYear,
        perMonth,
        perDay,
        reasons,
        classes,
        seatTypes,
        countries,
        continents,
        flightTypes,
        topAirlines,
        topAirports,
        topAircraft,
        topRoutes,
    }
}
