import type { FlightPoint, CalculatedPointInfo, AircraftParams } from './types'

export function newGuid(): string {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
    const r = (Math.random() * 16) | 0
    const v = c === 'x' ? r : (r & 0x3) | 0x8
    return v.toString(16)
  })
}

export function calculateDistance(
  point1: FlightPoint,
  point2: FlightPoint,
  aircraftType: string,
  initialAltitude: number,
  downang: number,
  upang: number,
): number {
  if (!point1?.position || !point2?.position) return 0

  const R = 6371
  const { lat: lat1, lng: lon1 } = point1.position
  const { lat: lat2, lng: lon2 } = point2.position
  const alt1 = point1.altitude || 0
  const alt2 = point2.altitude || 0

  const toRad = (value: number) => (value * Math.PI) / 180
  const dLat = toRad(lat2 - lat1)
  const dLon = toRad(lon2 - lon1)

  const a =
    Math.sin(dLat / 2) * Math.sin(dLat / 2) +
    Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) *
    Math.sin(dLon / 2) * Math.sin(dLon / 2)

  const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a))
  const horizontalDistance = R * c

  const initialAltitudeKm = initialAltitude / 1000
  const altitude1Km = alt1 / 1000
  const altitude2Km = alt2 / 1000

  const descentAngleRad = toRad(downang || 0.01)
  const ascentAngleRad = toRad(upang || 0.01)

  if (aircraftType === 'Plane') {
    const ascentDist = Math.max(0, (initialAltitudeKm - altitude1Km) / Math.sin(ascentAngleRad))
    const descentDist = Math.max(0, (initialAltitudeKm - altitude2Km) / Math.sin(descentAngleRad))
    const hAscent = Math.max(0, ascentDist * Math.cos(ascentAngleRad))
    const hDescent = Math.max(0, descentDist * Math.cos(descentAngleRad))
    return horizontalDistance - (hDescent + hAscent) + Math.max(0, descentDist) + Math.max(0, ascentDist)
  }

  const ascentVertical = Math.abs(initialAltitudeKm - altitude1Km)
  const descentVertical = Math.abs(initialAltitudeKm - altitude2Km)
  return ascentVertical + horizontalDistance + descentVertical
}

const DEFAULT_OWM_BASE_URL = 'https://api.openweathermap.org/data/2.5'

function getOwmBaseUrl(): string {
  const raw = import.meta.env.VITE_OWM_BASE_URL
  if (!raw) return DEFAULT_OWM_BASE_URL
  return raw.replace(/\/+$/, '')
}

export async function getWeatherData(lat: number, lon: number) {
  const apiKey = import.meta.env.VITE_OWM_API_KEY
  if (!apiKey) return null
  const url = `${getOwmBaseUrl()}/weather?lat=${lat}&lon=${lon}&appid=${apiKey}&units=metric`
  try {
    const res = await fetch(url)
    const data = await res.json()
    return { windSpeed: data.wind.speed as number, windAngle: data.wind.deg as number }
  } catch {
    return null
  }
}

export async function calculateBatteryPercentUsed(
  groundSpeed: number,
  time: number,
  position: { lat: number; lon: number },
  aircraft: AircraftParams,
): Promise<number> {
  const weatherData = await getWeatherData(position.lat, position.lon)
  const airDensity = 1.05
  const groundSpeedMs = groundSpeed / 3.6
  const headwind = (weatherData?.windSpeed ?? 0) * Math.cos((Math.PI / 180) * (weatherData?.windAngle ?? 0))
  const effectiveAirspeed = groundSpeedMs + headwind
  const drag = 0.5 * airDensity * (effectiveAirspeed ** 2) * aircraft.dragCoefficient * aircraft.frontalArea
  const adjustedDrag = drag + aircraft.weight * 9.8 * 0.05

  let watts = aircraft.thrustWatts[aircraft.thrustWatts.length - 1].watts
  for (const item of aircraft.thrustWatts) {
    const thrustN = (item.thrust / 1000) * 9.8
    if (thrustN > adjustedDrag) { watts = item.watts; break }
  }
  const power = watts / aircraft.propellerEfficiency
  const energyUsed = power * time
  return Math.min((energyUsed / aircraft.batteryCapacity) * 100, 100)
}

export async function calculateAllPoints(
  points: FlightPoint[],
  aircraft: AircraftParams,
  initialAltitude: number,
): Promise<CalculatedPointInfo[]> {
  const infos: CalculatedPointInfo[] = [{ bat: 100, time: 0 }]
  for (let i = 1; i < points.length; i++) {
    const p1 = points[i - 1], p2 = points[i]
    const dist = calculateDistance(p1, p2, aircraft.type, initialAltitude, aircraft.downang, aircraft.upang)
    const time = dist / aircraft.speed
    const midPos = { lat: (p1.position.lat + p2.position.lat) / 2, lon: (p1.position.lng + p2.position.lng) / 2 }
    const pct = await calculateBatteryPercentUsed(aircraft.speed, time, midPos, aircraft)
    infos.push({ bat: infos[i - 1].bat - pct, time: infos[i - 1].time + time })
  }
  return infos
}

export function parseCoordinates(input: string): { lat: number; lng: number } | null {
  const cleaned = input.trim().replace(/[°NSEW]/gi, '')
  const parts = cleaned.split(/[,\s]+/).filter(Boolean)
  if (parts.length >= 2) {
    const lat = parseFloat(parts[0])
    const lng = parseFloat(parts[1])
    if (!isNaN(lat) && !isNaN(lng) && lat >= -90 && lat <= 90 && lng >= -180 && lng <= 180) {
      return { lat, lng }
    }
  }
  return null
}

export function getMockAircraftParams(): AircraftParams {
  return {
    type: 'Plane',
    downang: 40,
    upang: 45,
    weight: 3.4,
    speed: 80,
    frontalArea: 0.12,
    dragCoefficient: 0.45,
    batteryCapacity: 315,
    thrustWatts: [
      { thrust: 500, watts: 55.5 },
      { thrust: 750, watts: 91.02 },
      { thrust: 1000, watts: 137.64 },
      { thrust: 1250, watts: 191 },
      { thrust: 1500, watts: 246 },
      { thrust: 1750, watts: 308 },
      { thrust: 2000, watts: 381 },
    ],
    propellerEfficiency: 0.95,
  }
}
