"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const node_child_process_1 = require("node:child_process");
const node_path_1 = require("node:path");
const node_util_1 = require("node:util");
const _chai_spec_1 = require("./_chai.spec");
const ExifTool_1 = require("./ExifTool");
const ExiftoolPath_1 = require("./ExiftoolPath");
const GeolocationTags_1 = require("./GeolocationTags");
const execFileAsync = (0, node_util_1.promisify)(node_child_process_1.execFile);
async function getGeolocationTags(lat, lon) {
    const exiftool = await (0, ExiftoolPath_1.exiftoolPath)();
    const { stdout } = await execFileAsync(exiftool, [
        "-api",
        `geolocation=${lat},${lon}`,
        "-json",
    ]);
    const results = JSON.parse(stdout);
    return results[0];
}
// Tags that are always returned by ExifTool for valid coordinates
const alwaysReturnedTags = new Set([
    "GeolocationBearing",
    "GeolocationCity",
    "GeolocationCountry",
    "GeolocationCountryCode",
    "GeolocationDistance",
    "GeolocationFeatureCode",
    "GeolocationFeatureType",
    "GeolocationPopulation",
    "GeolocationPosition",
    "GeolocationRegion",
    "GeolocationSubregion",
    "GeolocationTimeZone",
]);
// Tags that may not be returned in normal results
const optionalTags = new Set(["GeolocationWarning"]);
describe("GeolocationTags", function () {
    this.timeout(10000);
    this.slow(2000);
    // Expected values from ExifTool - this validates tag name casing
    const sfExploratorium = {
        GeolocationBearing: 227,
        GeolocationCity: "Chinatown",
        GeolocationCountry: "United States",
        GeolocationCountryCode: "US",
        GeolocationDistance: "0.80 km",
        GeolocationFeatureCode: "PPLX",
        GeolocationFeatureType: "Section of Populated Place",
        GeolocationPopulation: 100000,
        GeolocationPosition: "37.7966, -122.4086",
        GeolocationRegion: "California",
        GeolocationSubregion: "City and County of San Francisco",
        GeolocationTimeZone: "America/Los_Angeles",
        GeolocationWarning: undefined, // Not returned for valid coordinates
    };
    const eiffelTower = {
        GeolocationBearing: 319,
        GeolocationCity: "Neuilly-sur-Seine",
        GeolocationCountry: "France",
        GeolocationCountryCode: "FR",
        GeolocationDistance: "3.33 km",
        GeolocationFeatureCode: "PPL",
        GeolocationFeatureType: "Populated Place",
        GeolocationPopulation: 61000,
        GeolocationPosition: "48.8845, 2.2697",
        GeolocationRegion: "Île-de-France",
        GeolocationSubregion: "Hauts-de-Seine",
        GeolocationTimeZone: "Europe/Paris",
        GeolocationWarning: undefined,
    };
    // Southern hemisphere test case
    const sydneyOperaHouse = {
        GeolocationBearing: 251,
        GeolocationCity: "The Rocks",
        GeolocationCountry: "Australia",
        GeolocationCountryCode: "AU",
        GeolocationDistance: "0.69 km",
        GeolocationFeatureCode: "PPLL",
        GeolocationFeatureType: "Populated Locality",
        GeolocationPopulation: 2100,
        GeolocationPosition: "-33.8592, 151.2083",
        GeolocationRegion: "New South Wales",
        GeolocationSubregion: "City of Sydney",
        GeolocationTimeZone: "Australia/Sydney",
        GeolocationWarning: undefined,
    };
    const testLocations = [
        {
            name: "SF Exploratorium",
            lat: 37.802078,
            lon: -122.4026305,
            expected: sfExploratorium,
        },
        {
            name: "Eiffel Tower",
            lat: 48.8583736,
            lon: 2.2919064,
            expected: eiffelTower,
        },
        {
            name: "Sydney Opera House",
            lat: -33.856784,
            lon: 151.215297,
            expected: sydneyOperaHouse,
        },
    ];
    for (const loc of testLocations) {
        describe(loc.name, () => {
            let result;
            before(async () => {
                result = await getGeolocationTags(loc.lat, loc.lon);
            });
            it("returns expected tag values", () => {
                for (const tagName of GeolocationTags_1.GeolocationTagNames.values) {
                    if (optionalTags.has(tagName))
                        continue;
                    (0, _chai_spec_1.expect)(result[tagName]).to.eql(loc.expected[tagName], `Tag ${tagName} mismatch`);
                }
            });
            it("all returned tag names match GeolocationTagNames casing", () => {
                const returnedKeys = Object.keys(result).filter((k) => k !== "SourceFile");
                const unknownTags = [];
                const knownTagsSet = new Set(GeolocationTags_1.GeolocationTagNames.values);
                for (const key of returnedKeys) {
                    if (!knownTagsSet.has(key)) {
                        unknownTags.push(key);
                    }
                }
                (0, _chai_spec_1.expect)(unknownTags).to.eql([], `ExifTool returned geolocation tags not in GeolocationTagNames: ${unknownTags.join(", ")}. ` +
                    `This may indicate a casing mismatch or missing tags.`);
            });
            it("all expected tags are returned by ExifTool", () => {
                const returnedKeys = new Set(Object.keys(result));
                for (const tagName of alwaysReturnedTags) {
                    (0, _chai_spec_1.expect)(returnedKeys.has(tagName)).to.eql(true, `Expected tag "${tagName}" not returned by ExifTool`);
                }
            });
        });
    }
    describe("reading from image file", () => {
        let et;
        before(() => {
            et = new ExifTool_1.ExifTool({ geolocation: true });
        });
        after(() => (0, _chai_spec_1.end)(et));
        // Expected values when reading pixel.jpg with geolocation enabled
        // Note: GeolocationPosition format differs from raw exiftool output because
        // numericTags includes GeolocationPosition, so ExifTool uses -Tag# which
        // returns "lat lon" instead of "lat, lon"
        const pixelJpgExpected = {
            GeolocationBearing: 318,
            GeolocationCity: "El Granada",
            GeolocationCountry: "United States",
            GeolocationCountryCode: "US",
            GeolocationDistance: "2.60 km",
            GeolocationFeatureCode: "PPL",
            GeolocationFeatureType: "Populated Place",
            GeolocationPopulation: 5500,
            GeolocationPosition: "37.5027 -122.4694",
            GeolocationRegion: "California",
            GeolocationSubregion: "San Mateo County",
            GeolocationTimeZone: "America/Los_Angeles",
            GeolocationWarning: undefined,
        };
        it("returns geolocation tags when reading pixel.jpg", async () => {
            const tags = await et.read((0, node_path_1.join)(_chai_spec_1.testDir, "pixel.jpg"));
            for (const tagName of GeolocationTags_1.GeolocationTagNames.values) {
                if (optionalTags.has(tagName))
                    continue;
                (0, _chai_spec_1.expect)(tags[tagName]).to.eql(pixelJpgExpected[tagName], `Tag ${tagName} mismatch`);
            }
        });
        it("all returned geolocation tag names match GeolocationTagNames casing", async () => {
            const tags = await et.read((0, node_path_1.join)(_chai_spec_1.testDir, "pixel.jpg"));
            const returnedKeys = Object.keys(tags).filter((k) => k.startsWith("Geolocation"));
            const unknownTags = [];
            const knownTagsSet = new Set(GeolocationTags_1.GeolocationTagNames.values);
            for (const key of returnedKeys) {
                if (!knownTagsSet.has(key)) {
                    unknownTags.push(key);
                }
            }
            (0, _chai_spec_1.expect)(unknownTags).to.eql([], `ExifTool returned geolocation tags not in GeolocationTagNames: ${unknownTags.join(", ")}`);
        });
    });
});
//# sourceMappingURL=GeolocationTags.spec.js.map