/*
    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 Adw from "gi://Adw";
import Gtk from "gi://Gtk";
import Pango from "gi://Pango";
import { getShortName, getDisplayName } from "./placenames.js";
import { Location } from "../location.js";
import { gettext as _g } from "resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js";
import { isNoInternet } from "../utils.js";
const SEARCH_BASE = "https://nominatim.openstreetmap.org";
const SEARCH_ENDPOINT = `${SEARCH_BASE}/search`;
export async function searchDialog(parent, soup, cfg) {
    const dialog = new Gtk.Window({
        transient_for: parent,
        title: _g("Search Location"),
        modal: true,
        width_request: parent.get_width() * 0.75,
        height_request: parent.get_height() * 0.75
    });
    const page = new Adw.PreferencesPage();
    const group = new Adw.PreferencesGroup();
    const searchField = new Gtk.Entry({
        placeholder_text: _g("City, Neighborhood, etc.")
    });
    group.add(searchField);
    const searchButton = new Gtk.Button({
        label: _g("Search")
    });
    group.add(searchButton);
    searchField.connect("activate", () => {
        searchButton.emit("clicked");
    });
    const resultsLocList = [];
    const stringList = new Gtk.StringList();
    const selModel = new Gtk.SingleSelection({
        can_unselect: false,
        model: stringList
    });
    // Added later
    const addBtn = new Gtk.Button({
        label: _g("Add")
    });
    const resultsView = new Gtk.ListView({
        orientation: Gtk.Orientation.VERTICAL,
        model: selModel,
        factory: setupListFactory(addBtn),
        margin_top: 20,
        margin_bottom: 20
    });
    const resultsScroll = new Gtk.ScrolledWindow({
        child: resultsView,
        vexpand: true,
        hexpand: true
    });
    group.add(resultsScroll);
    const licenseLabel = new Gtk.Label({
        wrap: true,
        wrap_mode: Pango.WrapMode.WORD_CHAR,
        css_classes: ["simpleweather-small", "simpleweather-center"]
    });
    group.add(licenseLabel);
    group.add(addBtn);
    return new Promise((resolve, reject) => {
        searchButton.connect("clicked", () => {
            searchButton.sensitive = false;
            const a = {
                search: searchField.text,
                licenseLabel,
                resultsList: stringList,
                soup,
                currentLocNames: cfg.getLocations().map(l => l.getName())
            };
            fetchNominatim(a).then(locArr => {
                const oldLen = resultsLocList.length;
                resultsLocList.splice(0, oldLen, ...locArr);
                populateList(stringList, locArr);
                searchButton.sensitive = true;
            }).catch(e => {
                if (isNoInternet(e)) {
                    console.error(e);
                    showNoInternetDialog(dialog);
                    searchButton.sensitive = true;
                }
                else
                    reject(e);
            });
        });
        addBtn.connect("clicked", () => {
            const item = resultsLocList[selModel.selected];
            if (item) {
                const countryCode = item.countryCode;
                const retLoc = Location.newCoords(item.friendlyName, item.lat, item.lon, { countryCode });
                resolve(retLoc);
                dialog.close();
            }
        });
        dialog.connect("close-request", () => {
            resolve(null);
        });
        page.add(group);
        dialog.set_child(page);
        dialog.show();
    });
}
function showNoInternetDialog(parent) {
    const alert = new Gtk.AlertDialog({
        message: _g("No Internet")
    });
    alert.show(parent);
}
function setupListFactory(addBtn) {
    const f = new Gtk.SignalListItemFactory();
    f.connect("setup", (_, item) => {
        const label = new Gtk.Label({
            margin_top: 5,
            margin_bottom: 5
        });
        item.set_child(label);
        const dblClick = new Gtk.GestureClick();
        dblClick.connect("pressed", (_g, nClicks, _x, _y) => {
            if (nClicks === 2) {
                // Double-clicking is same as clicking add
                addBtn.emit("clicked");
            }
        });
        label.add_controller(dblClick);
    });
    f.connect("bind", (_, item) => {
        const label = item.get_child();
        const val = item.get_item();
        label.set_label(val.get_string());
    });
    return f;
}
function populateList(resultsList, locs) {
    const names = locs.map(l => l.buttonName);
    const oldLen = resultsList.get_n_items();
    resultsList.splice(0, oldLen, names);
}
async function fetchNominatim(a) {
    const params = {
        format: "jsonv2",
        addressdetails: "1",
        q: a.search
    };
    const resp = await a.soup.fetchJson(SEARCH_ENDPOINT, params, true);
    if (!resp.is2xx)
        throw new Error(`Nominatim status code ${resp.status}.`);
    const b = resp.body;
    if (!b[0]) {
        a.licenseLabel.label = _g("No results.");
        return [];
    }
    // British spelling of license
    a.licenseLabel.label = b[0]?.licence ?? _g("No copyright information available.");
    const list = [];
    for (let result of b) {
        const place = result;
        const name = getDisplayName(place);
        const lat = parseFloat(place.lat);
        const lon = parseFloat(place.lon);
        let friendlyName = getShortName(place) ?? name;
        // If a duplicate name exists use the longer one
        if (a.currentLocNames.includes(friendlyName))
            friendlyName = name;
        list.push({
            buttonName: name,
            friendlyName,
            lat,
            lon,
            countryCode: place.address?.country_code
        });
    }
    return list;
}
