# Copyright 2026, Jiri Eischmann <jiri@eischmann.cz> and the meshy contributors
# SPDX-License-Identifier: GPL-3.0-or-later

"""Shared helpers for chat_view and channels_view."""

import gi

gi.require_version("Gtk", "4.0")
gi.require_version("Adw", "1")
gi.require_version("Shumate", "1.0")
from gi.repository import Adw, Gio, GObject, Gtk, Shumate
from meshy.views import (
    _CONTACT_TYPE_ICONS,
    _contact_pick_factory_bind,
    _contact_pick_factory_setup,
    _contact_pick_factory_unbind,
    _ContactPickItem,
    create_shumate_map,
)

CONTACT_TYPE_ICONS = _CONTACT_TYPE_ICONS


def ensure_loc_map(outer, lat, lon):
    """Create or update the inline location map widget on a chat item."""
    if outer._loc_map_widget is not None:
        outer._loc_viewport.set_location(lat, lon)
        outer._loc_marker.set_location(lat, lon)
        outer._loc_map_frame.set_child(outer._loc_map_widget)
        return

    from meshy.views.map_view import MapView

    loc_map, loc_marker_layer, loc_viewport = create_shumate_map(zoom_level=14)
    loc_map.set_vexpand(False)
    loc_map.set_hexpand(True)
    loc_map.set_size_request(100, 150)
    loc_map.get_scale().set_visible(False)
    loc_map.set_show_zoom_buttons(False)
    loc_map.get_license().set_visible(False)

    loc_marker_widget = MapView._build_marker_widget(
        0.26, 0.52, 0.96, "find-location-symbolic", None, show_label=False
    )
    loc_marker = Shumate.Marker()
    loc_marker.set_child(loc_marker_widget)
    loc_marker_layer.add_marker(loc_marker)

    loc_viewport.set_zoom_level(14)
    loc_viewport.set_location(lat, lon)
    loc_marker.set_location(lat, lon)
    outer._loc_map_widget = loc_map
    outer._loc_viewport = loc_viewport
    outer._loc_marker = loc_marker
    outer._loc_map_frame.set_child(loc_map)


def show_location_map(window, lat, lon):
    """Open a dialog with the shared location on a map."""
    from meshy.views.map_view import MapView

    dialog, map_w, m_layer, vp = MapView.open_map_dialog(window, _("Shared Location"))
    marker = MapView.create_marker(
        0.26, 0.52, 0.96, "find-location-symbolic", _("Shared"), lat, lon
    )
    m_layer.add_marker(marker)

    dev = window.device_info
    if dev and dev.latitude is not None and dev.longitude is not None:
        self_marker = MapView.create_marker(
            0.90,
            0.16,
            0.22,
            "avatar-default-symbolic",
            dev.name or _("My Device"),
            dev.latitude,
            dev.longitude,
        )
        m_layer.add_marker(self_marker)

    vp.set_zoom_level(14)
    vp.set_location(lat, lon)
    dialog.present(window)


def open_location_external(btn, lat, lon):
    """Launch external map app for the given coordinates."""
    launcher = Gtk.UriLauncher.new(f"geo:{lat},{lon}")
    launcher.launch(None, None, None, None)


def share_contact_dialog(window, contacts, send_callback):
    """Show a contact picker dialog and call send_callback(contact) on selection."""
    if not contacts:
        return

    builder = Gtk.Builder.new_from_resource(
        "/page/codeberg/sesivany/Meshy/ui/share-contact-dialog.ui"
    )
    dialog = builder.get_object("share_dialog")
    search_btn = builder.get_object("share_search_btn")
    search_entry = builder.get_object("share_search_entry")
    list_view = builder.get_object("share_list_view")
    status_label = builder.get_object("share_status_label")

    search_btn.bind_property("active", search_entry, "visible", GObject.BindingFlags.SYNC_CREATE)
    search_entry.connect("stop-search", lambda _e: search_btn.set_active(False))

    store = Gio.ListStore(item_type=_ContactPickItem)
    for c in sorted(contacts, key=lambda c: c.name.lower()):
        store.append(_ContactPickItem(c))

    custom_filter = Gtk.CustomFilter.new(_share_filter_func, search_entry)

    def _on_search_changed(*_args):
        custom_filter.changed(Gtk.FilterChange.DIFFERENT)

    search_entry.connect("search-changed", _on_search_changed)

    filter_model = Gtk.FilterListModel(model=store, filter=custom_filter)
    selection = Gtk.NoSelection(model=filter_model)
    list_view.set_model(selection)

    def _on_share(contact):
        send_callback(contact)
        dialog.close()

    factory = Gtk.SignalListItemFactory()
    factory.connect("setup", lambda f, li: _contact_pick_factory_setup(f, li, _("Share")))
    factory.connect("bind", lambda f, li: _contact_pick_factory_bind(f, li, _on_share))
    factory.connect("unbind", _contact_pick_factory_unbind)
    list_view.set_factory(factory)

    def _on_activate(lv, pos):
        item = filter_model.get_item(pos)
        if item:
            _on_share(item.contact)

    list_view.connect("activate", _on_activate)

    total = store.get_n_items()
    status_label.set_label(_("{total} contacts").format(total=total) if total else _("No contacts"))

    dialog._refs = (store, custom_filter, filter_model, selection, factory)
    dialog.present(window)


def _share_filter_func(item, search_entry):
    q = search_entry.get_text().lower()
    return not q or q in item.contact.name.lower()


def share_location(window, send_callback):
    """Share the device's current GPS coordinates via send_callback(text)."""
    dev = window.device_info
    if not dev or dev.latitude is None or dev.longitude is None:
        dialog = Adw.AlertDialog(
            heading=_("Location Not Available"),
            body=_("Your companion does not have a GPS location."),
        )
        dialog.add_response("ok", _("OK"))
        dialog.present(window)
        return
    send_callback(f"{dev.latitude:.6f},{dev.longitude:.6f}")


def share_location_map(window, send_callback):
    """Open a map picker to choose and share a location via send_callback(text)."""
    from meshy.views import open_map_picker

    dev = window.device_info
    lat = dev.latitude if dev and dev.latitude is not None else 0.0
    lon = dev.longitude if dev and dev.longitude is not None else 0.0
    open_map_picker(
        window,
        _("Share Location"),
        _("Share"),
        lat,
        lon,
        lambda la, lo: send_callback(f"{la:.6f},{lo:.6f}"),
    )
