// 数据来源：FAA Aircraft Registry。美国 FAA 官方注册库，每日更新，MASTER.txt 包含 Mode-S Hex。
// 链接：https://www.faa.gov/licenses_certificates/aircraft_certification/aircraft_registry/releasable_aircraft_download
// 下载：https://registry.faa.gov/database/ReleasableAircraft.zip
// 官方更新要求：FAA 下载页说明文件每日刷新。本地告警策略：超过 24 小时提示更新。

#include "../server/libarchive.h"
#include "Resource_Utils.h"

#include <SQLiteCpp/Transaction.h>

#include <fstream>
#include <stdexcept>

namespace {

const std::vector<std::string> kFaaColumns = {
    "n_number", "serial_number", "aircraft_mfr_model_code", "engine_mfr_model_code",
    "year_mfr", "registrant_type", "name", "street", "street2", "city", "state",
    "zip_code", "region", "county", "country", "last_action_date", "cert_issue_date",
    "certification", "type_aircraft", "type_engine", "status_code", "mode_s_code",
    "fractional_ownership", "airworthiness_date", "other_names_1", "other_names_2",
    "other_names_3", "other_names_4", "other_names_5", "expiration_date",
    "unique_id", "kit_mfr", "kit_model", "icao24"
};
const std::vector<std::string> kFaaPrimaryKey = {"icao24"};

class Faa_Aircraft_Registry_Resource final : public External_Resources {
public:
    Faa_Aircraft_Registry_Resource()
        : External_Resources("faa_aircraft_registry",
                             "faa_registry/MASTER.txt",
                             "https://registry.faa.gov/database/ReleasableAircraft.zip",
                             "FAA 官方可公开下载的美国飞机注册库，MASTER.txt 包含 Mode-S Hex 注册信息。",
                             86400) {}

    void create_table(SQLite::Database& db) const override {
        db.exec(R"sql(
            CREATE TABLE IF NOT EXISTS faa_aircraft_registry (
              n_number TEXT, serial_number TEXT, aircraft_mfr_model_code TEXT,
              engine_mfr_model_code TEXT, year_mfr TEXT, registrant_type TEXT,
              name TEXT, street TEXT, street2 TEXT, city TEXT, state TEXT,
              zip_code TEXT, region TEXT, county TEXT, country TEXT,
              last_action_date TEXT, cert_issue_date TEXT, certification TEXT,
              type_aircraft TEXT, type_engine TEXT, status_code TEXT,
              mode_s_code TEXT, fractional_ownership TEXT, airworthiness_date TEXT,
              other_names_1 TEXT, other_names_2 TEXT, other_names_3 TEXT,
              other_names_4 TEXT, other_names_5 TEXT, expiration_date TEXT,
              unique_id TEXT, kit_mfr TEXT, kit_model TEXT,
              icao24 TEXT NOT NULL PRIMARY KEY
            );
        )sql");
    }

protected:
    bool fetch(const std::filesystem::path& cache_pos,
               const bool force_download) const override {
        const auto master_file = source_file(cache_pos);
        if (!force_download) return false;
        const auto zip_file = cache_pos / "ReleasableAircraft.zip";
        External_Database_Utils::download_to_file(download_url, zip_file);
        unarchive_file(zip_file, cache_pos / "faa_registry");
        return true;
    }

    std::size_t import_file(SQLite::Database& db,
                            const std::filesystem::path& source_file) const override {
        auto master_file = source_file;
        if (source_file.extension() == ".zip") {
            const auto output_dir = source_file.parent_path() / "faa_registry";
            unarchive_file(source_file, output_dir);
            master_file = output_dir / "MASTER.txt";
        }

        std::ifstream input(master_file, std::ios::binary);
        if (!input) throw std::runtime_error("Cannot open FAA MASTER.txt: " +
                                             master_file.string());

        SQLite::Transaction transaction(db);
        db.exec("DELETE FROM faa_aircraft_registry");
        SQLite::Statement statement(
            db, External_Database_Utils::make_upsert_sql(
                    name, kFaaColumns, kFaaPrimaryKey));
        std::vector<std::string> fields;
        External_Database_Utils::read_csv_row(input, fields, ',');  // 跳过表头。
        std::size_t row_count = 0;
        while (External_Database_Utils::read_csv_row(input, fields, ',')) {
            if (fields.size() < kFaaColumns.size()) fields.resize(kFaaColumns.size());
            const auto icao24 = External_Database_Utils::normalize_key(fields[33]);
            if (icao24.empty()) continue;

            statement.reset();
            statement.clearBindings();
            for (std::size_t index = 0; index < kFaaColumns.size(); ++index) {
                auto value = External_Database_Utils::normalize_field(fields[index]);
                if (index == 33) value = icao24;
                External_Database_Utils::bind_optional(
                    statement, static_cast<int>(index + 1), value);
            }
            statement.exec();
            ++row_count;
        }
        transaction.commit();
        return row_count;
    }

    [[nodiscard]] const std::vector<std::string>& primary_key_columns() const override {
        return kFaaPrimaryKey;
    }
};

}  // 命名空间

std::unique_ptr<External_Resources> make_faa_aircraft_registry_resource() {
    return std::make_unique<Faa_Aircraft_Registry_Resource>();
}
