/*
    Copyright 2025 Roman Lefler

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
import { gettext as _g } from "./gettext.js";
import { getMyLocation } from "./myLocation.js";
import { OmModel } from "./openmeteo-models.js";
const latlonRegex = /^([0-9]+\.?[0-9]*),([0-9]+\.?[0-9]*)$/;
export class Location {
    /**
     * True if this is the special location "here"
     */
    #isHere;
    /**
     * If this is here, the city name that is resolved.
     */
    #hereCityName;
    #omModel;
    #countryCode;
    #lat;
    #lon;
    #name;
    constructor(name, isHere, lat, lon, data = {}) {
        this.#name = name;
        this.#isHere = isHere ?? false;
        this.#lat = lat;
        this.#lon = lon;
        this.#omModel = data.omModel ?? OmModel.AUTO;
        this.#countryCode = data.countryCode;
    }
    getName() {
        if (this.#name)
            return this.#name;
        const txt = _g("My Location");
        if (this.#hereCityName)
            return `${txt} - ${this.#hereCityName}`;
        else
            return txt;
    }
    getRawName() {
        return this.#name ?? null;
    }
    getDescription() {
        return this.#isHere ? _g("My Location") : this.getCoordsString();
    }
    isHere() {
        return this.#isHere;
    }
    async latLon() {
        if (this.#isHere) {
            const myLoc = await getMyLocation();
            this.#hereCityName = myLoc.city ?? undefined;
            return { lat: myLoc.lat, lon: myLoc.lon };
        }
        else
            return { lat: this.#lat, lon: this.#lon };
    }
    getCoordsString() {
        const isNorth = this.#lat >= 0;
        const isEast = this.#lon >= 0;
        const latFmt = isNorth ? _g("%f\u00B0N") : _g("%f\u00B0S");
        const lonFmt = isEast ? _g("%f\u00B0E") : _g("%f\u00B0W");
        const latStr = Math.abs(this.#lat).toLocaleString();
        const lonStr = Math.abs(this.#lon).toLocaleString();
        return `${latFmt.format(latStr)} ${lonFmt.format(lonStr)}`;
    }
    getOmModel() {
        return this.#omModel;
    }
    // Currently unused, may be useful in future
    getCountryCode() {
        return this.#countryCode ?? null;
    }
    toString() {
        const obj = {
            name: this.#name
        };
        if (this.#isHere)
            obj.isHere = true;
        if (this.#lat) {
            obj.lat = this.#lat;
            obj.lon = this.#lon;
        }
        if (this.#omModel !== OmModel.AUTO) {
            obj.omm = this.#omModel;
        }
        if (this.#countryCode) {
            obj.cc = this.#countryCode;
        }
        return JSON.stringify(obj);
    }
    static parse(s) {
        let obj;
        try {
            obj = JSON.parse(s);
        }
        catch (e) {
            return null;
        }
        const containsLat = typeof obj.lat !== "undefined";
        const containsLon = typeof obj.lon !== "undefined";
        // Only here can omit the name
        if (!obj.isHere && !obj.name)
            return null;
        // isHere must be undefined or bool
        if (typeof obj.isHere !== "undefined" && typeof obj.isHere !== "boolean")
            return null;
        // lat must be undefined or number
        if (containsLat && typeof obj.lat !== "number")
            return null;
        // lon must be undefined or number
        if (containsLon && typeof obj.lon !== "number")
            return null;
        // either neither lat or lon or both lon and lat
        if (containsLat !== containsLon)
            return null;
        if (typeof obj.cc !== "undefined" && typeof obj.cc !== "string")
            return null;
        return new Location(obj.name ?? undefined, obj.isHere, obj.lat, obj.lon, { omModel: obj.omModel, countryCode: obj.cc });
    }
    static newCoords(name, lat, lon, data = {}) {
        return new Location(name, false, lat, lon, data);
    }
    static newHere(name, data = {}) {
        return new Location(name, true, undefined, undefined, data);
    }
}
