export type ZoneStatus = 'FREE' | 'CONDITIONAL' | 'FORBIDDEN'

export interface AnacZone {
  id: string
  name: string
  type: string
  status: ZoneStatus
  geometry: GeoJSON.Geometry
  lowerLimit: { value: number; uom: string } | null
  upperLimit: { value: number; uom: string } | null
  message?: string
  authorityName?: string
  authorityUrl?: string
  authorityEmail?: string
  authorityPhone?: string
  schedule?: string
}

export function zoneRestrictionToStatus(restriction: string): ZoneStatus {
  switch (restriction) {
    case 'PROHIBITED': return 'FORBIDDEN'
    case 'CONDITIONAL': return 'CONDITIONAL'
    case 'NO_RESTRICTION': return 'FREE'
    default: return 'FREE'
  }
}

function horizontalProjectionToGeoJSON(proj: any): GeoJSON.Geometry | null {
  if (!proj) return null
  if (proj.type === 'Polygon') {
    return { type: 'Polygon', coordinates: proj.coordinates }
  }
  if (proj.type === 'Circle') {
    const [lng, lat] = proj.center as [number, number]
    const r = (proj.radius as number) ?? 500
    const latR = r / 111320
    const lngR = r / (111320 * Math.cos((lat * Math.PI) / 180))
    const pts = 32
    const ring = Array.from({ length: pts + 1 }, (_, i) => {
      const a = (i / pts) * 2 * Math.PI
      return [lng + lngR * Math.cos(a), lat + latR * Math.sin(a)]
    })
    return { type: 'Polygon', coordinates: [ring] }
  }
  return null
}

export function parseAnacED318Zones(raw: unknown): AnacZone[] {
  const features: unknown[] = (raw as any)?.features ?? []
  const result: AnacZone[] = []

  for (const f of features as any[]) {
    const props = f.properties ?? {}
    const geo = f.geometry ?? {}

    // Name: pick PT text, else EN, else identifier
    const nameArr: Array<{ text: string; lang: string }> = props.name ?? []
    const namePT = nameArr.find((n) => n.lang === 'PT')?.text
    const nameEN = nameArr.find((n) => n.lang === 'EN')?.text
    const name = namePT ?? nameEN ?? props.identifier ?? ''

    // Restriction mapping
    let status: ZoneStatus = 'FREE'
    if (props.type === 'PROHIBITED') status = 'FORBIDDEN'
    else if (props.type === 'REQ_AUTHORIZATION') status = 'CONDITIONAL'

    // Geometry: Point + Circle extent → polygon approximation
    if (geo.type !== 'Point' || !Array.isArray(geo.coordinates)) continue
    const [lng, lat] = geo.coordinates as [number, number]
    const radius: number = geo.extent?.radius ?? 500
    const pts = 32
    const latR = radius / 111320
    const lngR = radius / (111320 * Math.cos((lat * Math.PI) / 180))
    const ring = Array.from({ length: pts + 1 }, (_, i) => {
      const a = (i / pts) * 2 * Math.PI
      return [lng + lngR * Math.cos(a), lat + latR * Math.sin(a)]
    })
    const geometry: GeoJSON.Geometry = { type: 'Polygon', coordinates: [ring] }

    const layer = geo.layer ?? {}

    const msgArr: Array<{ text: string; lang: string }> = props.message ?? []
    const msgPT = msgArr.find((m) => m.lang === 'PT')?.text
    const msgEN = msgArr.find((m) => m.lang === 'EN')?.text
    const message = msgPT ?? msgEN

    const authority = (props.zoneAuthority ?? [])[0] ?? {}
    const authorityUrl: string | undefined = authority.siteURL
    const authorityEmail: string | undefined = authority.email
    const authorityPhone: string | undefined = authority.phone ? `+${authority.phone}` : undefined
    const authorityNameArr: Array<{ text: string; lang: string }> = authority.name ?? []
    const authorityName = (authorityNameArr.find((n) => n.lang === 'PT') ?? authorityNameArr[0])?.text

    // Schedule: pick first schedule entry if present
    const sched = (props.limitedApplicability ?? [])[0]?.schedule?.[0]
    let schedule: string | undefined
    if (sched) {
      const EVENT_LABELS: Record<string, string> = {
        BMCT: 'nascente', EMCT: 'fim crepúsculo matutino',
        BECT: 'início crepúsculo vespertino', EECT: 'poente',
        SUNRISE: 'nascer do sol', SUNSET: 'pôr do sol',
        SS: 'pôr do sol', SR: 'nascer do sol',
      }
      const days = sched.day?.includes('ANY') ? 'Todos os dias' : (sched.day ?? []).join(', ')
      const start = EVENT_LABELS[sched.startEvent] ?? sched.startEvent ?? sched.startTime ?? ''
      const end = EVENT_LABELS[sched.endEvent] ?? sched.endEvent ?? sched.endTime ?? ''
      schedule = start && end ? `${days}: ${start} – ${end}` : days || undefined
    }

    result.push({
      id: props.identifier ?? String(f.id ?? ''),
      name,
      type: props.type ?? '',
      status,
      geometry,
      lowerLimit: layer.lower != null ? { value: layer.lower, uom: layer.uom ?? 'M' } : null,
      upperLimit: layer.upper != null ? { value: layer.upper, uom: layer.uom ?? 'M' } : null,
      message,
      authorityName,
      authorityUrl,
      authorityEmail,
      authorityPhone,
      schedule,
    })
  }
  return result
}

export function parseAnacZones(raw: unknown): AnacZone[] {
  const features: unknown[] = (raw as any)?.features ?? []
  const result: AnacZone[] = []
  for (const f of features as any[]) {
    const geometry = horizontalProjectionToGeoJSON(f.geometry?.[0]?.horizontalProjection)
    if (!geometry) continue // skip features without renderable geometry
    result.push({
      id: f.identifier ?? '',
      name: f.name ?? '',
      type: f.type ?? '',
      status: zoneRestrictionToStatus(f.restriction ?? ''),
      geometry,
      lowerLimit: f.geometry?.[0]?.lowerLimit != null ? { value: f.geometry[0].lowerLimit, uom: f.geometry[0].uomDimensions ?? 'M' } : null,
      upperLimit: f.geometry?.[0]?.upperLimit != null ? { value: f.geometry[0].upperLimit, uom: f.geometry[0].uomDimensions ?? 'M' } : null,
    })
  }
  return result
}

const CACHE_TTL_MS = 60 * 60 * 1000

let _cacheED269: { data: AnacZone[]; expiresAt: number } | null = null
const ANAC_ED269_URL = 'https://dnt.anac.pt/json/UASZoneVersion%2022042026083205.json'

export async function getAnacZones(): Promise<AnacZone[]> {
  if (_cacheED269 && Date.now() < _cacheED269.expiresAt) return _cacheED269.data
  const res = await fetch(ANAC_ED269_URL, { next: { revalidate: 3600 }, headers: { Accept: 'application/json' } })
  if (!res.ok) throw new Error(`ANAC ED-269 fetch failed: ${res.status}`)
  const raw = await res.json()
  const data = parseAnacZones(raw)
  _cacheED269 = { data, expiresAt: Date.now() + CACHE_TTL_MS }
  return data
}

let _cacheED318: { data: AnacZone[]; expiresAt: number } | null = null
const ANAC_ED318_URL = 'https://dnt.anac.pt/ED-318_json/UASZoneVersion%20ED-318%2022042026083042.json'

export async function getAnacED318Zones(): Promise<AnacZone[]> {
  if (_cacheED318 && Date.now() < _cacheED318.expiresAt) return _cacheED318.data
  const res = await fetch(ANAC_ED318_URL, { next: { revalidate: 3600 }, headers: { Accept: 'application/json' } })
  if (!res.ok) throw new Error(`ANAC ED-318 fetch failed: ${res.status}`)
  const raw = await res.json()
  const data = parseAnacED318Zones(raw)
  _cacheED318 = { data, expiresAt: Date.now() + CACHE_TTL_MS }
  return data
}

export function anacZonesToGeoJSON(zones: AnacZone[]): GeoJSON.FeatureCollection {
  return {
    type: 'FeatureCollection',
    features: zones.map((z) => ({
      type: 'Feature',
      id: z.id,
      geometry: z.geometry,
      properties: { id: z.id, name: z.name, status: z.status, lowerLimit: z.lowerLimit, upperLimit: z.upperLimit, message: z.message, authorityName: z.authorityName, authorityUrl: z.authorityUrl, authorityEmail: z.authorityEmail, authorityPhone: z.authorityPhone, schedule: z.schedule },
    })),
  }
}
