#pragma once

#include "../Data_Source/Database.h"

#include <iomanip>
#include <sstream>

// https://wiki.jetvision.de/wiki/Radarcape:Software_Features#Aircraft_List_JSON_Service
struct Aircraft_List_JSON_Service_O
{
    size_t times; //自定义添加出现的次数  用于显示的优先级
    time_t uti{}; // Time of last message: Seconds since UNIX epoch
    std::uint32_t ns{}; // Time of last message: Nanoseconds since Second epoch
    std::uint32_t day_second{}; // Time of last message: Nanoseconds since Second epoch
    std::string hex; // ICAO Mode-S or c, in Hex format
    RET<std::string> fli; // Flight Identification
    RET<std::string> ava; // Flight data: available flight data sources
    std::string src; //  Flight data: Source
    std::string cla; // Subclass of ADS-B data
    RET<double> lat; // Flight data: Latitude (-90 to 90º)
    RET<double> lon; // Flight data: Longitude (-180 to 180º)
    RET<double> alt; // Flight data: Barometric uncalibrated altitude (ft)
    RET<double> spd; // Flight data: Ground Speed (kt)
    RET<double> trk; // Flight data: True track (0-360º)
    RET<double> vrt; // Flight data: Vertical Rate (ft/min)
    std::string gda; //	Airborne/Ground
    std::string cat; //	Aircraft category
    RET<std::string> org; // Origin           DB       起点机场
    RET<std::string> dst; // Destination      DB       目标机场
    RET<std::string> opr; // Operator         DB
    RET<std::string> typ; // Type             DB
    RET<std::string> reg; // Registration     DB
    RET<std::string> squ; //  Mode-A (Squawk)
    RET<std::string> cou; // Country
    RET<double> dis; // Distance (km or NM depending on configuration)
    RET<size_t> tru;
    // Trust count Number of Mode-S frames successfully decoded from this A/C. Statistically it's possible that for a very low count the A/C does not actually exist
    int dbm{}; // Approximate signal level in dBm;
    RET<time_t> lla; // int Age of last Position (s)
    RET<int> tmp; // Temperature (ºC)
    RET<int> wsp; // Wind Speed (kt)
    RET<double> wdi; // Wind from Direction (0-360º)
    RET<int> mop; // ADS-B MOPS version;
    RET<std::string> spi; // SPI (Squawk ident);
    RET<bool> alr; // Alert status
    RET<double> ias; // IAS
    RET<double> tas; // TAS
    RET<double> hdgm; // Magnetic Heading
    RET<std::string> hdgt; // True Heading
    RET<std::string> qnhs; // Selected QNH
    RET<std::string> alts; // Selected QNH
    RET<double> hdgs; // Selected Heading
    RET<double> altg; // GNSS elipsoidal altitude (ft)
    RET<std::string> pic; // Asterix PIC
    RET<std::string> tcm; // ACAS/TCAS status
    RET<std::string> ape; // Autopilot engaged
    RET<int> sil; // ADS-B SIL
    RET<std::string> sda; // ADS-B SDA
    RET<int> nacp; // ADS-B SDA
    RET<int> pest; // Number of position estimations per second
    RET<size_t> nocl; // Number of sensors providing data aircraft
    RET<std::string> tq; // Time quality of this entry
    // RET<SSR::Vortex_Type> vortex_type; // 飞机类型
    static Psc::JSON build_view_model()
    {
        auto columns = Psc::JSON::array();
        const auto add_column = [&columns](const char* key, const char* label, const char* type,
                                           const char* default_sort_order = nullptr,
                                           const char* fixed = nullptr,
                                           const std::uint32_t width = 110)
        {
            auto column = Psc::JSON::object();
            column.append({"key", key});
            column.append({"label", label});
            column.append({"type", type});
            column.append({"width", width});
            column.append({"sortable", std::string(type) != "index"});
            if (std::string(type) == "number")
            {
                column.append({"filter", "range"});
            }
            else if (std::string(type) == "text")
            {
                column.append({"filter", "text"});
            }
            else if (std::string(type) == "boolean")
            {
                column.append({"filter", "boolean"});
            }
            if (default_sort_order != nullptr)
            {
                column.append({"defaultSortOrder", default_sort_order});
            }
            if (fixed != nullptr)
            {
                column.append({"fixed", fixed});
            }
            columns.append(std::move(column));
        };

        add_column("index", "序号", "index", nullptr, "left", 64);
        add_column("hex", "识别码（ICAO）", "text", nullptr, "left", 132);
        add_column("fli", "呼号", "text", nullptr, "left", 120);
        auto time_column = Psc::JSON::object();
        time_column.append({"key", "time"});
        time_column.append({"label", "时间"});
        time_column.append({"type", "timestamp"});
        time_column.append({"width", 190});
        time_column.append({"sortable", true});
        time_column.append({"secondsKey", "uti"});
        time_column.append({"nanosecondsKey", "ns"});
        columns.append(std::move(time_column));

        add_column("times", "Mode-S 消息数", "number", nullptr, nullptr, 132);
        add_column("ava", "数据来源标识", "text");
        add_column("src", "首选数据源", "text");
        add_column("cla", "ADS-B数据子类", "text");
        add_column("lat", "纬度", "number");
        add_column("lon", "经度", "number", "descend");
        add_column("alt", "高度（米）", "number");
        add_column("spd", "地速（节）", "number");
        add_column("trk", "航向（真）", "number");
        add_column("vrt", "垂直速度（ft/min）", "number", nullptr, nullptr, 150);
        add_column("gda", "空中/地面状态", "text");
        add_column("cat", "机型分类", "text");
        add_column("org", "起飞机场", "text");
        add_column("dst", "目的机场", "text");
        add_column("opr", "航空公司", "text");
        add_column("typ", "机型", "text");
        add_column("reg", "注册号", "text");
        add_column("squ", "应答机编码", "text");
        add_column("cou", "国家", "text");
        add_column("dis", "接收器距离", "number");
        add_column("tru", "信任值", "number");
        add_column("dbm", "信号强度（dBm）", "number", nullptr, nullptr, 140);
        add_column("lla", "位置数据延迟（秒）", "number");
        add_column("tmp", "温度（℃）", "number");
        add_column("wsp", "风速（节）", "number");
        add_column("wdi", "风向（°）", "number");
        add_column("mop", "ADS-B协议版本", "number");
        add_column("spi", "识别应答（SPI）", "text");
        add_column("alr", "告警状态", "boolean");
        add_column("ias", "指示空速（IAS）", "number", nullptr, nullptr, 132);
        add_column("tas", "真空速（TAS）", "number", nullptr, nullptr, 132);
        add_column("hdgm", "磁航向", "number");
        add_column("hdgt", "真航向", "text");
        add_column("qnhs", "气压设定（QNH）", "text", nullptr, nullptr, 140);
        add_column("alts", "选择高度", "text");
        add_column("hdgs", "选择航向", "number");
        add_column("altg", "GNSS椭球高度（英尺）", "number");
        add_column("pic", "Asterix PIC", "text");
        add_column("tcm", "防撞系统状态", "text");
        add_column("ape", "自动驾驶启用", "text");
        add_column("sil", "系统完整性等级（SIL）", "number", nullptr, nullptr, 160);
        add_column("sda", "系统设计保证（SDA）", "text", nullptr, nullptr, 160);
        add_column("nacp", "位置精度（NACp）", "number", nullptr, nullptr, 150);
        add_column("pest", "位置估算次数每秒", "number");
        add_column("nocl", "提供数据的接收机数", "number");
        add_column("tq", "时间质量", "text");
        // add_column("vortex_type", "涡流类型", "text");

        auto model = Psc::JSON::object();
        model.append({"columns", std::move(columns)});
        return model;
    }

    static constexpr std::uint32_t view_model_schema_version = 1;

    static const std::string& view_model_schema_hash()
    {
        static const std::string hash = []
        {
            auto model = build_view_model();
            model.append({"schema_version", view_model_schema_version});
            const auto serialized = model.to_json_string();
            std::uint64_t value = 14695981039346656037ull;
            for (const unsigned char byte : serialized)
            {
                value ^= byte;
                value *= 1099511628211ull;
            }
            std::ostringstream stream;
            stream << std::hex << std::setfill('0') << std::setw(16) << value;
            return stream.str();
        }();
        return hash;
    }

    static const Psc::JSON& view_model()
    {
        static const Psc::JSON model = []
        {
            auto value = build_view_model();
            value.append({"schema_version", view_model_schema_version});
            value.append({"schema_hash", view_model_schema_hash()});
            return value;
        }();
        return model;
    }

    Psc::JSON toJson()
    {
        auto ret = Psc::JSON::object();
        ADD_Json(times);
        ADD_Json(uti);
        ADD_Json(ns);
        ADD_Json(day_second);
        ADD_Json(hex);
        ADD_Json_RET(fli);
        ADD_Json_RET(ava);
        ADD_Json(src);
        ADD_Json(cla);
        ADD_Json_RET(lat);
        ADD_Json_RET(lon);
        ADD_Json_RET(alt);
        ADD_Json_RET(spd);
        ADD_Json_RET(trk);
        ADD_Json_RET(vrt);
        ADD_Json(gda);
        ADD_Json(cat);
        ADD_Json_RET(org);
        ADD_Json_RET(dst);
        ADD_Json_RET(opr);
        ADD_Json_RET(typ);
        ADD_Json_RET(reg);
        ADD_Json_RET(squ);
        ADD_Json_RET(cou);
        ADD_Json_RET(dis);
        ADD_Json(tru);
        ADD_Json(dbm);
        ADD_Json_RET(lla);
        ADD_Json_RET(tmp);
        ADD_Json_RET(wsp);
        ADD_Json_RET(wdi);
        ADD_Json_RET(mop);
        ADD_Json_RET(spi);
        ADD_Json_RET(alr);
        ADD_Json_RET(ias);
        ADD_Json_RET(tas);
        ADD_Json_RET(hdgm);
        ADD_Json_RET(hdgt);
        ADD_Json_RET(qnhs);
        ADD_Json_RET(alts);
        ADD_Json_RET(hdgs);
        ADD_Json_RET(altg);
        ADD_Json_RET(pic);
        ADD_Json_RET(tcm);
        ADD_Json_RET(ape);
        ADD_Json_RET(sil);
        ADD_Json_RET(sda);
        ADD_Json_RET(nacp);
        ADD_Json_RET(pest);
        ADD_Json_RET(nocl);
        ADD_Json_RET(tq);
        // ADD_Json_RET(vortex_type);
        return ret;
    }


    // https://wiki.jetvision.de/wiki/Radarcape:Software_Features#Aircraft_List_JSON_Service
    static Aircraft_List_JSON_Service_O to_That(DataBase* db, Aircraft* info)
    {
        Aircraft_List_JSON_Service_O ret;
        // 航线查询结果保存在 Aircraft 中，仅在首次加载或 callsign 变化时重新读取数据库。
        ret.times = info->times;
        ret.uti = info->timestamp;
        ret.ns = info->mlat_timestamp.nanosec;
        ret.day_second = info->mlat_timestamp.daysec;
        ret.hex = info->icao; // TODO not c
        // fli	Flight Identification		Mode-S	From ADS-B or BDS2,0 as specified on ICAO Annex 10, Volume IV, Table 3-9; "?" when A/C reports loss of interface
        ret.fli = info->bds20_call_sign();
        // ava ava	Flight data: available flight data sources			One letter per available flight data sources. A=ADSB, M=Jetvision MLAT, F=FlightAware MLAT, O=OGN, L=FLARM
        // ret.ava
        ret.ava = "暂不支持";
        // ret.src
        ret.src = "暂不支持";
        // ret.cla
        ret.cla = "暂不支持";
        RET<SSR::CPR::Position> pos = info->air_pos_track_list.last();
        if (pos.has_value())
        {
            ret.lat = pos.value().lat;
            ret.lon = pos.value().lon;
        }
        ret.alt = info->altitude_meter();
        ret.spd = info->speed();
        ret.trk = info->air_magnetic_heading();
        ret.vrt = info->vertical_rate();
        // 飞机在地面还是空中 G for on ground, A for airborne (if TIS-B then lowercase g or a)
        ret.gda = info->is_on_ground() ? "G" : "A";
        auto vt = info->vortex_type();
        if (vt.has_value())
        {
            ret.cat = Vortex_Type_to_radarcape_code(vt.value());
        }
        // =============== 来自DB 航班数据库 ================
        auto route_info = info->external_database_row("vrs_routes");
        if (!route_info)
        {
            route_info = info->external_database_row("adsblol_vrs_standing_data_routes");
        }
        if (!route_info)
        {
            route_info = info->external_database_row("vradarserver_standing_data_routes");
        }
        if (route_info)
        {
            const auto airport_codes = route_info->get("AirportCodes");
            if (airport_codes && !airport_codes->empty())
            {
                const auto first_separator = airport_codes->find('-');
                const auto last_separator = airport_codes->rfind('-');
                ret.org = airport_codes->substr(0, first_separator);
                ret.dst = last_separator == std::string::npos
                              ? *airport_codes
                              : airport_codes->substr(last_separator + 1);
            }
        }
        //ret.opr
        const auto opensky_info =
            info->external_database_row("opensky_aircraft_database");
        if (opensky_info)
        {
            ret.opr = opensky_info->get("operator");
        }
        //ret.typ
        if (opensky_info)
        {
            ret.typ = opensky_info->get("typecode");
        }
        //ret.reg
        if (opensky_info)
        {
            ret.reg = opensky_info->get("registration");
        }
        // ===============================
        // squ	Mode-A (Squawk)		Mode-S	While this is a Mode-A code,
        // it can only be correlated in Mode-S targets. Mode-A or Mode-A/C targets are not
        // displayed in decoded formats since they cannot be correlated with a <hex> value
        ret.squ = info->squawk();
        // cou	Country		<hex>	Country according to Mode-S allocation block if decodable, mostly unusable/invalid for FLARM A/C
        //ret.cou
        const auto faa_info = info->external_database_row("faa_aircraft_registry");
        if (faa_info)
        {
            ret.cou = faa_info->get("country");
        }
        // dis	Distance (km or NM depending on configuration)			To the Receiver GNSS location
        auto p = db->base_station.get_pos();
        if (p.has_value() && pos.has_value())
        {
            ret.dis = SSR::CPR::haversine(pos.value(), p.value());
        }
        ret.tru = info->times;
        ret.dbm = info->signal_level;
        //ret.lla
        ret.lla = std::time(nullptr) - info->timestamp;
        //ret.tmp
        ret.tmp = info->temperature();
        //ret.wsp
        ret.wsp = info->wind_speed();
        //ret.wdi
        ret.wdi = info->wind_direction();
        ret.mop = info->ADS_B_Ver();
        //ret.spi
        ret.spi = info->squawk();
        //ret.alr
        ret.alr = info->alart();
        auto air_speed = info->get_airspeed();
        if (air_speed.has_value())
        {
            auto& t = air_speed.value();
            auto type = t.get_airspeed_type();
            if (type == SSR::Airspeed_type::Indicated_airspeed_IAS)
            {
                ret.ias = air_speed.value().get_speed();
            }
            if (type == SSR::Airspeed_type::True_airspeed_TAS)
            {
                ret.tas = air_speed.value().get_speed();
            }
            ret.hdgm = air_speed.value().get_magnetic_heading();
            ret.hdgt = "暂不支持";
        }
        //ret.qnhs   Selected QNH
        ret.qnhs = "暂不支持";
        //ret.alts   Selected Altitude
        ret.alts = "暂不支持";
        //ret.hdgs   Selected Heading
        ret.hdgs = info->select_heading();
        auto it = info->get_speed_base();
        if (it.has_value())
        {
            auto i = it.value();
            i.get_GNSS_barometric_altitudes_difference();
            auto diff = i.get_GNSS_barometric_altitudes_difference();
            if (diff.has_value() && ret.alt.has_value())
            {
                ret.altg = diff.value() + ret.alt.value();
            }
        }
        //ret.pic
        ret.pic = "暂不支持";
        //ret.tcm
        ret.tcm = "暂不支持";
        // ape	Autopilot engaged	2	Mode-S
        //ret.ape
        ret.ape = "暂不支持";
        ret.sil = info->SIL();
        //ret.sda
        ret.sda = "暂不支持";
        ret.nacp = info->NACp();
        // pest	Number of position estimations per second		MLAT
        ret.pest = info->get_pest();
        // nocl	Number of sensors providing data aircraft		MLAT
        ret.nocl = 1;
        // tq	Time quality of this entry		Sensor	0: GNSS 1: Sensor NTP 2: Server NTP
        //ret.tq
        ret.tq = "暂不支持";
        // ret.vortex_type = info->vortex_type();
        return ret;
    }
};
