# Copyright (C) 2026 Danilo M. <danix@danix.xyz>
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 as published
# by the Free Software Foundation.
"""PyQt6 GUI for hyprsunset-qt."""

from __future__ import annotations

from PyQt6.QtWidgets import (
    QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
    QLabel, QLineEdit, QCheckBox, QSpinBox, QDoubleSpinBox, QPushButton,
    QGroupBox, QScrollArea,
)

from . import config as cfg
from . import daemon
from . import sun
from .settings import Settings


class ProfileRow(QWidget):
    def __init__(self, profile: cfg.Profile):
        super().__init__()
        lay = QHBoxLayout(self)
        lay.setContentsMargins(0, 0, 0, 0)

        self.time = QLineEdit(profile.time)
        self.time.setFixedWidth(70)

        self.identity = QCheckBox("identity")
        self.identity.setChecked(profile.identity)

        self.temp_on = QCheckBox("temp")
        self.temp_on.setChecked(profile.temperature is not None)
        self.temp = QSpinBox()
        self.temp.setRange(1000, 20000)
        self.temp.setValue(profile.temperature or 5500)

        self.gamma_on = QCheckBox("gamma")
        self.gamma_on.setChecked(profile.gamma is not None)
        self.gamma = QDoubleSpinBox()
        self.gamma.setRange(0.0, 2.0)
        self.gamma.setSingleStep(0.05)
        self.gamma.setValue(profile.gamma if profile.gamma is not None else 1.0)

        self.remove = QPushButton("✕")
        self.remove.setFixedWidth(28)

        for w in (QLabel("time"), self.time, self.identity,
                  self.temp_on, self.temp, self.gamma_on, self.gamma,
                  self.remove):
            lay.addWidget(w)
        lay.addStretch()

        self.temp_on.toggled.connect(self.temp.setEnabled)
        self.gamma_on.toggled.connect(self.gamma.setEnabled)
        self.temp.setEnabled(self.temp_on.isChecked())
        self.gamma.setEnabled(self.gamma_on.isChecked())

    def to_profile(self) -> cfg.Profile:
        return cfg.Profile(
            time=self.time.text().strip(),
            identity=self.identity.isChecked(),
            temperature=self.temp.value() if self.temp_on.isChecked() else None,
            gamma=self.gamma.value() if self.gamma_on.isChecked() else None,
        )


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("hyprsunset-qt")
        self.settings = Settings.load()
        self.rows: list[ProfileRow] = []

        central = QWidget()
        self.setCentralWidget(central)
        root = QVBoxLayout(central)

        # Daemon status bar
        bar = QHBoxLayout()
        self.status = QLabel()
        restart_btn = QPushButton("Restart")
        restart_btn.clicked.connect(self.on_restart)
        bar.addWidget(self.status)
        bar.addStretch()
        bar.addWidget(restart_btn)
        root.addLayout(bar)

        # Location group
        loc = QGroupBox("Location")
        loc_lay = QVBoxLayout(loc)
        coords = QHBoxLayout()
        self.lat = QLineEdit(self.settings.lat)
        self.lon = QLineEdit(self.settings.lon)
        self.auto = QCheckBox("auto")
        self.auto.setChecked(self.settings.auto_detect)
        detect = QPushButton("Detect")
        detect.clicked.connect(self.on_detect)
        for w in (QLabel("Lat"), self.lat, QLabel("Lon"), self.lon,
                  self.auto, detect):
            coords.addWidget(w)
        loc_lay.addLayout(coords)
        fetch_row = QHBoxLayout()
        fetch_btn = QPushButton("Fetch sun times")
        fetch_btn.clicked.connect(self.on_fetch)
        self.sun_label = QLabel("sunrise —  sunset —")
        fetch_row.addWidget(fetch_btn)
        fetch_row.addWidget(self.sun_label)
        fetch_row.addStretch()
        loc_lay.addLayout(fetch_row)
        root.addWidget(loc)

        # Profiles group
        prof_box = QGroupBox("Profiles")
        prof_outer = QVBoxLayout(prof_box)
        add_row = QHBoxLayout()
        add_btn = QPushButton("+ Add")
        add_btn.clicked.connect(lambda: self.add_row(cfg.Profile(time="0:00")))
        add_row.addStretch()
        add_row.addWidget(add_btn)
        prof_outer.addLayout(add_row)
        self.rows_lay = QVBoxLayout()
        prof_outer.addLayout(self.rows_lay)
        root.addWidget(prof_box)

        # Bottom actions
        actions = QHBoxLayout()
        preview_btn = QPushButton("Live preview")
        preview_btn.clicked.connect(self.on_preview)
        save_btn = QPushButton("Save + Restart")
        save_btn.clicked.connect(self.on_save)
        actions.addWidget(preview_btn)
        actions.addStretch()
        actions.addWidget(save_btn)
        root.addLayout(actions)

        for p in cfg.read_config():
            self.add_row(p)
        self.refresh_status()
        self.load_cached_sun()

    # --- helpers ---
    def add_row(self, profile: cfg.Profile) -> None:
        row = ProfileRow(profile)
        row.remove.clicked.connect(lambda: self.remove_row(row))
        self.rows.append(row)
        self.rows_lay.addWidget(row)

    def remove_row(self, row: ProfileRow) -> None:
        self.rows.remove(row)
        row.setParent(None)

    def profiles(self) -> list[cfg.Profile]:
        return [r.to_profile() for r in self.rows]

    def refresh_status(self) -> None:
        running = daemon.is_running()
        self.status.setText(
            "Daemon: ● running" if running else "Daemon: ○ stopped"
        )

    def save_settings(self) -> None:
        self.settings.lat = self.lat.text().strip()
        self.settings.lon = self.lon.text().strip()
        self.settings.auto_detect = self.auto.isChecked()
        self.settings.save()

    # --- actions ---
    def on_restart(self) -> None:
        daemon.restart(self.settings.daemon_command)
        self.refresh_status()

    def on_detect(self) -> None:
        try:
            lat, lon = sun.geolocate()
            self.lat.setText(lat)
            self.lon.setText(lon)
        except Exception as e:  # noqa: BLE001
            self.sun_label.setText(f"detect failed: {e}")

    def on_fetch(self) -> None:
        self.save_settings()
        lat, lon = self.lat.text().strip(), self.lon.text().strip()
        try:
            data = sun.fetch_sun(lat, lon)
        except Exception as e:  # noqa: BLE001
            self.sun_label.setText(f"fetch failed: {e}")
            return
        data["lat"], data["lon"] = lat, lon
        sun.write_cache(data, self.settings.cache_path_expanded())
        self.apply_sun(data)

    def load_cached_sun(self) -> None:
        data = sun.read_cache(self.settings.cache_path_expanded())
        if data:
            self.apply_sun(data)

    def apply_sun(self, data: dict) -> None:
        r = data.get("results", {})
        sunrise = sun.to_local_hm(r["sunrise"]) if r.get("sunrise") else "—"
        sunset = sun.to_local_hm(r["sunset"]) if r.get("sunset") else "—"
        self.sun_label.setText(f"sunrise {sunrise}  sunset {sunset}")
        profiles = self.profiles()
        di = cfg.day_index(profiles)
        ni = cfg.night_index(profiles)
        if di is not None and sunrise != "—":
            self.rows[di].time.setText(sunrise)
        if ni is not None and sunset != "—":
            self.rows[ni].time.setText(sunset)

    def on_preview(self) -> None:
        profiles = self.profiles()
        ni = cfg.night_index(profiles)
        target = profiles[ni] if ni is not None else (
            profiles[0] if profiles else None
        )
        if target is None:
            return
        daemon.live_preview(
            temperature=target.temperature,
            gamma=target.gamma,
            identity=target.identity,
        )

    def on_save(self) -> None:
        profiles = self.profiles()
        for p in profiles:
            if not cfg.valid_time(p.time):
                self.sun_label.setText(f"invalid time: {p.time!r}")
                return
            if p.temperature is not None and not cfg.valid_temperature(p.temperature):
                self.sun_label.setText(f"invalid temperature: {p.temperature}")
                return
            if p.gamma is not None and not cfg.valid_gamma(p.gamma):
                self.sun_label.setText(f"invalid gamma: {p.gamma}")
                return
        cfg.write_config(profiles)
        self.save_settings()
        daemon.restart(self.settings.daemon_command)
        self.refresh_status()
        self.sun_label.setText("saved + restarted")
