import { cfg } from './config.mjs';
import { resolve, dirname } from 'path';
import { fileURLToPath } from 'url';
import * as fs from 'node:fs';
import Database from 'better-sqlite3';
import { fromCsv } from '@ztimson/utils';

const DIR         = dirname(fileURLToPath(import.meta.url));
const DATA        = resolve(DIR, '../data');
const DB_PATH     = resolve(DATA, 'aircraft.db');
const CSV_CACHE   = resolve(DATA, 'aircraft_db.csv');
const SHAPES_PATH = resolve(DATA, 'shapes.json');
const history     = new Map();
const MAX_HISTORY = 500;

const CSV_URL = 'https://s3.opensky-network.org/data-samples/metadata/aircraft-database-complete-2024-06.csv';

const MILITARY_OPERATORS  = ['air force', 'army', 'navy', 'marine', 'coast guard', 'military', 'defence', 'defense', 'luftwaffe', 'RAF', 'USAF', 'USN', 'USMC'];
const CARGO_OPERATORS     = ['fedex', 'ups', 'dhl', 'cargo', 'freight', 'logistic', 'atlas air', 'kalitta', 'air freight'];
const PASSENGER_OPERATORS = ['airlines', 'airways', 'air ', 'jet', 'easyjet', 'ryanair', 'delta', 'united', 'american', 'southwest', 'lufthansa', 'emirates', 'british'];
const MILITARY_CLASSES    = ['H1M', 'H2M', 'L1M', 'L2M', 'L4M', 'A0'];

let db;

export async function initAircraftDb() {
	if (!fs.existsSync(DATA)) fs.mkdirSync(DATA, { recursive: true });

	const missing = !fs.existsSync(DB_PATH);
	if(missing) console.log(`✈️  Building database`);

	db = new Database(DB_PATH);
	db.exec(`
        CREATE TABLE IF NOT EXISTS aircraft (
            icao24          TEXT PRIMARY KEY,
            built           TEXT,
            categoryDescription TEXT,
            country         TEXT,
            engines         TEXT,
            class           TEXT,
            manufacturer    TEXT,
            model           TEXT,
            modes           TEXT,
            operator        TEXT,
            operatorCallsign TEXT,
            owner           TEXT,
            registration    TEXT,
            serialNumber    TEXT,
            aircraft        TEXT
        )
    `);

	if (missing) {
		const res = await fetch(CSV_URL);
		if (!res.ok) throw new Error(`HTTP ${res.status}`);
		const text = await res.text();
		fs.writeFileSync(CSV_CACHE, text);

		const csv = fromCsv(text, true);
		const insert = db.prepare(`
            INSERT OR REPLACE INTO aircraft VALUES (
                @icao24, @built, @categoryDescription, @country, @engines,
                @class, @manufacturer, @model, @modes, @operator,
                @operatorCallsign, @owner, @registration, @serialNumber, @aircraft
            )
        `);

		const insertMany = db.transaction(rows => {
			for (const row of rows) insert.run(row);
		});

		insertMany(csv.map(row => ({
			icao24:              (row.icao24 || '').toUpperCase(),
			built:               row.built || null,
			categoryDescription: row.categoryDescription || null,
			country:             row.country || null,
			engines:             row.engines || null,
			class:               row.icaoAircraftClass || null,
			manufacturer:        row.manufacturerName || row.manufacturerIcao || null,
			model:               row.model || null,
			modes:               row.modes || null,
			operator:            row.operator || null,
			operatorCallsign:    row.operatorCallsign || null,
			owner:               row.owner || null,
			registration:        row.registration || null,
			serialNumber:        row.serialNumber || null,
			aircraft:            row.typecode || null,
		})));

		fs.unlinkSync(CSV_CACHE);
		console.log(`✈️  Aircraft imported: ${csv.length}`);
	} else {
		const count = db.prepare('SELECT COUNT(*) as c FROM aircraft').get();
		console.log(`✈️  Aircraft loaded: ${count.c}`);
	}
}

function wordMatch(text, keyword) {
	if (!text) return false;
	const escaped = keyword.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
	return new RegExp(`(?<![\\w])${escaped}(?![\\w])`, 'i').test(text);
}

export function classifyAircraft(row) {
	if (!row) return 'unknown';

	const matchesAny = (fields, list) =>
		fields.some(f => list.some(k => wordMatch(f, k)));

	const operatorFields = [row.operator, row.operatorCallsign];
	const ownerFields    = [row.owner];
	const allFields      = [...operatorFields, ...ownerFields, row.categoryDescription];

	if (MILITARY_CLASSES.includes(row.class) || matchesAny(allFields, MILITARY_OPERATORS))  return 'military';
	if (row.categoryDescription?.toLowerCase().includes('cargo') || matchesAny(operatorFields, CARGO_OPERATORS)) return 'cargo';
	if (matchesAny(operatorFields, PASSENGER_OPERATORS)) return 'passenger';
	if (row.owner && !row.operator) return 'private';

	return 'unknown';
}

export function enrichAircraft(a) {
	if (!a.hex) return a;
	const row = db.prepare('SELECT * FROM aircraft WHERE icao24 = ?').get(a.hex.toUpperCase());
	if (!row) return a;
	return { ...a, ...row, type: classifyAircraft(row) };
}

export async function getShapes() {
	return JSON.parse(await fs.promises.readFile(SHAPES_PATH, 'utf8'));
}

export async function getADSB() {
	const { ADSB_URL } = cfg();
	if (!ADSB_URL) return [];
	const r = await fetch(`${ADSB_URL}:8080/data/aircraft.json`);
	const j = await r.json();
	const aircraft = j.aircraft || [];

	for (const a of aircraft) {
		if (!a.hex || !a.lat || !a.lon) continue;
		const key = a.hex.toLowerCase();
		if (!history.has(key)) history.set(key, []);
		const trail = history.get(key);
		trail.push({ latitude: a.lat, longitude: a.lon, altitude: a.alt_baro || 0, ts: Date.now() });
		if (trail.length > MAX_HISTORY) trail.shift();
	}

	return aircraft.map(enrichAircraft);
}

export async function getAirTrafficHistory(icao) {
	return { history: history.get(icao?.toLowerCase()) || [] };
}
