/** @odoo-module **/
/**
 * Fusion Clock - Portal Clock-In/Out Interaction (Odoo 19)
 *
 * Handles: GPS verification, clock in/out actions, live timer,
 * sound effects, persistent state, location selection, and UI animations.
 */

import { Interaction } from "@web/public/interaction";
import { registry } from "@web/core/registry";
import { rpc } from "@web/core/network/rpc";

export class FusionClockPortal extends Interaction {
    static selector = "#fusion-clock-app";

    setup() {
        this.isCheckedIn = this.el.dataset.checkedIn === "true";
        this.enableSounds = this.el.dataset.enableSounds === "true";
        this.checkInTime = null;
        this.timerInterval = null;
        this.selectedLocationId = null;

        if (this.el.dataset.checkInTime) {
            this.checkInTime = new Date(this.el.dataset.checkInTime + "Z");
        }

        // If server didn't provide check-in data, try localStorage
        if (!this.isCheckedIn || !this.checkInTime) {
            this._restoreState();
        } else {
            this._saveState();
        }

        // Load locations
        const locDataEl = document.getElementById("fclk-locations-data");
        this.locations = [];
        if (locDataEl) {
            try { this.locations = JSON.parse(locDataEl.textContent); } catch (e) {}
        }
        if (this.locations.length > 0) {
            this.selectedLocationId = this.locations[0].id;
        }

        // Start live clock
        this._updateCurrentTime();
        this.clockInterval = setInterval(() => this._updateCurrentTime(), 1000);

        // Start timer if checked in
        if (this.isCheckedIn && this.checkInTime) {
            this._startTimer();
            this._updateUIForClockIn({
                location_name: this.el.dataset.locationName || "",
            });
        }

        this._updateDateDisplay();

        // Event listeners
        this._setupEventListeners();

        // Visibility sync -- also sync on load to verify with server
        this._onVisibilityChange = () => this._syncOnVisibilityChange();
        document.addEventListener("visibilitychange", this._onVisibilityChange);
        this._syncTimeout = setTimeout(() => this._syncOnVisibilityChange(), 3000);
    }

    destroy() {
        this._stopTimer();
        if (this.clockInterval) clearInterval(this.clockInterval);
        if (this._syncTimeout) clearTimeout(this._syncTimeout);
        if (this._onVisibilityChange) {
            document.removeEventListener("visibilitychange", this._onVisibilityChange);
        }
    }

    _setupEventListeners() {
        const clockBtn = document.getElementById("fclk-clock-btn");
        if (clockBtn) {
            this._onClockClick = (e) => this._onClockButtonClick(e);
            clockBtn.addEventListener("click", this._onClockClick);
        }

        const locationCard = document.getElementById("fclk-location-card");
        if (locationCard && this.locations.length > 1) {
            locationCard.addEventListener("click", () => {
                const modal = document.getElementById("fclk-location-modal");
                if (modal) modal.style.display = "flex";
            });
        }

        const reasonSubmitBtn = document.getElementById("fclk-reason-submit");
        if (reasonSubmitBtn) {
            reasonSubmitBtn.addEventListener("click", () => this._submitReason());
        }

        const leaveBtn = document.getElementById("fclk-leave-btn");
        if (leaveBtn) {
            leaveBtn.addEventListener("click", () => {
                const modal = document.getElementById("fclk-leave-modal");
                if (modal) modal.style.display = "flex";
            });
        }

        const leaveSubmitBtn = document.getElementById("fclk-leave-submit");
        if (leaveSubmitBtn) {
            leaveSubmitBtn.addEventListener("click", () => this._submitLeave());
        }

        const clockoutConfirmBtn = document.getElementById("fclk-clockout-confirm-btn");
        if (clockoutConfirmBtn) {
            clockoutConfirmBtn.addEventListener("click", () => this._confirmClockOut());
        }

        document.querySelectorAll("[data-dismiss]").forEach((btn) => {
            btn.addEventListener("click", () => {
                const targetId = btn.dataset.dismiss;
                const modal = document.getElementById(targetId);
                if (modal) modal.style.display = "none";
            });
        });

        document.querySelectorAll(".fclk-modal-item").forEach((item) => {
            item.addEventListener("click", () => {
                this.selectedLocationId = parseInt(item.dataset.id);
                const nameEl = document.getElementById("fclk-location-name");
                const addrEl = document.getElementById("fclk-location-address");
                if (nameEl) nameEl.textContent = item.dataset.name;
                if (addrEl) addrEl.textContent = item.dataset.address;
                const modal = document.getElementById("fclk-location-modal");
                if (modal) modal.style.display = "none";
            });
        });
    }

    // =========================================================================
    // Clock Action
    // =========================================================================

    _onClockButtonClick(e) {
        e.preventDefault();
        const btn = document.getElementById("fclk-clock-btn");
        if (!btn || btn.disabled) return;

        if (this.isCheckedIn) {
            this._showClockOutConfirmation();
            return;
        }

        this._beginClockAction();
    }

    _showClockOutConfirmation() {
        const modal = document.getElementById("fclk-clockout-confirm-modal");
        if (!modal) {
            this._beginClockAction();
            return;
        }

        const checkinEl = document.getElementById("fclk-confirm-checkin-time");
        const durationEl = document.getElementById("fclk-confirm-duration");

        if (checkinEl && this.checkInTime) {
            const h = this.checkInTime.getHours();
            const m = this.checkInTime.getMinutes();
            const ampm = h >= 12 ? "PM" : "AM";
            const hour12 = h % 12 || 12;
            checkinEl.textContent = hour12 + ":" + (m < 10 ? "0" : "") + m + " " + ampm;
        }

        if (durationEl && this.checkInTime) {
            const diff = Math.max(0, Math.floor((new Date() - this.checkInTime) / 1000));
            const dh = Math.floor(diff / 3600);
            const dm = Math.floor((diff % 3600) / 60);
            durationEl.textContent = dh + "h " + dm + "m";
        }

        modal.style.display = "flex";
    }

    _confirmClockOut() {
        const modal = document.getElementById("fclk-clockout-confirm-modal");
        if (modal) modal.style.display = "none";
        this._beginClockAction();
    }

    _beginClockAction() {
        const btn = document.getElementById("fclk-clock-btn");
        if (!btn || btn.disabled) return;
        btn.disabled = true;

        const ripple = btn.querySelector(".fclk-btn-ripple");
        if (ripple) {
            ripple.classList.remove("fclk-ripple-active");
            void ripple.offsetWidth;
            ripple.classList.add("fclk-ripple-active");
        }

        this._showGPSOverlay();

        if (!navigator.geolocation) {
            this._hideGPSOverlay();
            this._showToast("Geolocation is not supported by your browser.", "error");
            btn.disabled = false;
            return;
        }

        navigator.geolocation.getCurrentPosition(
            (pos) => {
                this._performClockAction(pos.coords.latitude, pos.coords.longitude, pos.coords.accuracy);
            },
            async () => {
                let lat = 0, lng = 0;
                try {
                    const ipResp = await fetch("https://ipapi.co/json/");
                    if (ipResp.ok) {
                        const ipData = await ipResp.json();
                        if (ipData.latitude && ipData.longitude) {
                            lat = ipData.latitude;
                            lng = ipData.longitude;
                        }
                    }
                } catch {
                    // IP geolocation also unavailable
                }
                this._hideGPSOverlay();
                this._performClockAction(lat, lng, lat ? 5000 : 0);
            },
            { enableHighAccuracy: true, timeout: 15000, maximumAge: 0 }
        );
    }

    async _performClockAction(lat, lng, accuracy) {
        const btn = document.getElementById("fclk-clock-btn");
        try {
            const result = await rpc("/fusion_clock/clock_action", {
                latitude: lat,
                longitude: lng,
                accuracy: accuracy,
                source: "portal",
            });

            this._hideGPSOverlay();
            if (btn) btn.disabled = false;

            if (result.requires_reason) {
                this._showReasonModal();
                return;
            }

            if (result.error) {
                this._showToast(result.error, "error");
                this._shakeButton();
                return;
            }

            if (result.action === "clock_in") {
                this.isCheckedIn = true;
                this.checkInTime = new Date(result.check_in + "Z");
                this.el.dataset.locationName = result.location_name || "";
                this._updateUIForClockIn(result);
                this._startTimer();
                this._playSound("in");
                this._showToast(result.message, "success");
                this._saveState();
            } else if (result.action === "clock_out") {
                this.isCheckedIn = false;
                this._updateUIForClockOut(result);
                this._stopTimer();
                this._playSound("out");
                this._showToast(result.message, "success");
                this._clearState();
            }
        } catch (err) {
            this._hideGPSOverlay();
            this._showToast("Network error. Please try again.", "error");
            if (btn) btn.disabled = false;
        }
    }

    // =========================================================================
    // UI Updates
    // =========================================================================

    _updateUIForClockIn(data) {
        const dot = document.getElementById("fclk-status-dot");
        const statusText = document.getElementById("fclk-status-text");
        const timerLabel = document.getElementById("fclk-timer-label");
        const btnLabel = document.getElementById("fclk-btn-label");
        const btn = document.getElementById("fclk-clock-btn");
        const playIcon = document.getElementById("fclk-btn-icon-play");
        const stopIcon = document.getElementById("fclk-btn-icon-stop");

        if (dot) dot.classList.add("fclk-dot-active");
        if (statusText) statusText.textContent = "Clocked In";
        if (timerLabel) timerLabel.textContent = "Time Elapsed";
        if (btnLabel) btnLabel.textContent = "Tap to Clock Out";
        if (btn) btn.classList.add("fclk-clock-btn-out");
        if (playIcon) playIcon.style.display = "none";
        if (stopIcon) stopIcon.style.display = "block";

        if (data.location_name) {
            const locEl = document.getElementById("fclk-location-name");
            if (locEl) locEl.textContent = data.location_name;
        }
    }

    _updateUIForClockOut(data) {
        const dot = document.getElementById("fclk-status-dot");
        const statusText = document.getElementById("fclk-status-text");
        const timerLabel = document.getElementById("fclk-timer-label");
        const btnLabel = document.getElementById("fclk-btn-label");
        const btn = document.getElementById("fclk-clock-btn");
        const playIcon = document.getElementById("fclk-btn-icon-play");
        const stopIcon = document.getElementById("fclk-btn-icon-stop");
        const timer = document.getElementById("fclk-timer");

        if (dot) dot.classList.remove("fclk-dot-active");
        if (statusText) statusText.textContent = "Not Clocked In";
        if (timerLabel) timerLabel.textContent = "Ready to Clock In";
        if (btnLabel) btnLabel.textContent = "Tap to Clock In";
        if (btn) btn.classList.remove("fclk-clock-btn-out");
        if (playIcon) playIcon.style.display = "block";
        if (stopIcon) stopIcon.style.display = "none";
        if (timer) timer.textContent = "00 : 00 : 00";

        if (data.net_hours !== undefined) {
            const todayEl = document.getElementById("fclk-today-hours");
            if (todayEl) {
                const current = parseFloat(todayEl.textContent) || 0;
                todayEl.textContent = (current + data.net_hours).toFixed(1) + "h";
            }
            const weekEl = document.getElementById("fclk-week-hours");
            if (weekEl) {
                const currentW = parseFloat(weekEl.textContent) || 0;
                weekEl.textContent = (currentW + data.net_hours).toFixed(1) + "h";
            }
        }
    }

    // =========================================================================
    // Timer
    // =========================================================================

    _startTimer() {
        this._stopTimer();
        this._updateTimer();
        this.timerInterval = setInterval(() => this._updateTimer(), 1000);
    }

    _stopTimer() {
        if (this.timerInterval) {
            clearInterval(this.timerInterval);
            this.timerInterval = null;
        }
    }

    _updateTimer() {
        if (!this.checkInTime) return;
        const now = new Date();
        let diff = Math.max(0, Math.floor((now - this.checkInTime) / 1000));

        const h = Math.floor(diff / 3600);
        const m = Math.floor((diff % 3600) / 60);
        const s = diff % 60;

        const pad = (n) => (n < 10 ? "0" + n : "" + n);
        const timerEl = document.getElementById("fclk-timer");
        if (timerEl) {
            timerEl.textContent = pad(h) + " : " + pad(m) + " : " + pad(s);
        }
    }

    // =========================================================================
    // Date & Time Display
    // =========================================================================

    _updateDateDisplay() {
        const el = document.getElementById("fclk-date-display");
        if (!el) return;
        const days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
        const months = ["January", "February", "March", "April", "May", "June",
            "July", "August", "September", "October", "November", "December"];
        const now = new Date();
        el.textContent = days[now.getDay()] + ", " + months[now.getMonth()] + " " + now.getDate();
    }

    _updateCurrentTime() {
        const el = document.getElementById("fclk-current-time");
        if (!el) return;
        const now = new Date();
        let h = now.getHours();
        const m = now.getMinutes();
        const ampm = h >= 12 ? "PM" : "AM";
        h = h % 12 || 12;
        el.textContent = h + ":" + (m < 10 ? "0" : "") + m + " " + ampm;
    }

    // =========================================================================
    // Sound Effects
    // =========================================================================

    _playSound(type) {
        if (!this.enableSounds) return;
        try {
            const ctx = new (window.AudioContext || window.webkitAudioContext)();
            const osc = ctx.createOscillator();
            const gain = ctx.createGain();
            osc.connect(gain);
            gain.connect(ctx.destination);

            if (type === "in") {
                osc.type = "sine";
                osc.frequency.setValueAtTime(523, ctx.currentTime);
                osc.frequency.setValueAtTime(659, ctx.currentTime + 0.1);
                osc.frequency.setValueAtTime(784, ctx.currentTime + 0.2);
                gain.gain.setValueAtTime(0.3, ctx.currentTime);
                gain.gain.exponentialRampToValueAtTime(0.01, ctx.currentTime + 0.5);
                osc.start(ctx.currentTime);
                osc.stop(ctx.currentTime + 0.5);
            } else {
                osc.type = "sine";
                osc.frequency.setValueAtTime(784, ctx.currentTime);
                osc.frequency.setValueAtTime(523, ctx.currentTime + 0.15);
                gain.gain.setValueAtTime(0.25, ctx.currentTime);
                gain.gain.exponentialRampToValueAtTime(0.01, ctx.currentTime + 0.4);
                osc.start(ctx.currentTime);
                osc.stop(ctx.currentTime + 0.4);
            }
        } catch (e) {
            // Sounds are non-critical
        }
    }

    // =========================================================================
    // Toast Notifications
    // =========================================================================

    _showToast(msg, type) {
        const toast = document.getElementById("fclk-toast");
        const toastMsg = document.getElementById("fclk-toast-msg");
        const toastIcon = document.getElementById("fclk-toast-icon");
        if (!toast) return;

        toast.className = "fclk-toast fclk-toast-" + (type || "success");
        if (toastMsg) toastMsg.textContent = msg;
        if (toastIcon) {
            toastIcon.innerHTML = type === "error"
                ? '<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#ef4444" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="15" y1="9" x2="9" y2="15"/><line x1="9" y1="9" x2="15" y2="15"/></svg>'
                : '<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#10B981" stroke-width="2"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>';
        }

        toast.style.display = "flex";
        toast.style.animation = "fclk-toast-in 0.3s ease-out";

        setTimeout(() => {
            toast.style.animation = "fclk-toast-out 0.3s ease-in forwards";
            setTimeout(() => { toast.style.display = "none"; }, 300);
        }, 3000);
    }

    // =========================================================================
    // GPS Overlay
    // =========================================================================

    _showGPSOverlay() {
        const el = document.getElementById("fclk-gps-overlay");
        if (el) el.style.display = "flex";
    }

    _hideGPSOverlay() {
        const el = document.getElementById("fclk-gps-overlay");
        if (el) el.style.display = "none";
    }

    // =========================================================================
    // Shake Animation
    // =========================================================================

    _shakeButton() {
        const btn = document.getElementById("fclk-clock-btn");
        if (!btn) return;
        btn.classList.add("fclk-shake");
        setTimeout(() => { btn.classList.remove("fclk-shake"); }, 500);
    }

    // =========================================================================
    // Persistent State
    // =========================================================================

    _saveState() {
        try {
            localStorage.setItem("fclk_checked_in", "true");
            if (this.checkInTime) {
                localStorage.setItem("fclk_check_in_time", this.checkInTime.toISOString());
            }
            if (this.el.dataset.locationName) {
                localStorage.setItem("fclk_location_name", this.el.dataset.locationName);
            }
        } catch (e) {}
    }

    _clearState() {
        try {
            localStorage.removeItem("fclk_checked_in");
            localStorage.removeItem("fclk_check_in_time");
            localStorage.removeItem("fclk_location_name");
        } catch (e) {}
    }

    _restoreState() {
        try {
            const wasCheckedIn = localStorage.getItem("fclk_checked_in") === "true";
            const savedTime = localStorage.getItem("fclk_check_in_time");
            if (wasCheckedIn && savedTime) {
                const t = new Date(savedTime);
                if (!isNaN(t.getTime()) && (Date.now() - t.getTime()) < 24 * 60 * 60 * 1000) {
                    this.isCheckedIn = true;
                    this.checkInTime = t;
                    this.el.dataset.locationName = localStorage.getItem("fclk_location_name") || "";
                }
            }
        } catch (e) {}
    }

    // =========================================================================
    // Reason Modal & Leave Request
    // =========================================================================

    _showReasonModal() {
        const modal = document.getElementById("fclk-reason-modal");
        if (modal) modal.style.display = "flex";
    }

    async _submitReason() {
        const reasonEl = document.getElementById("fclk-reason-text");
        const timeEl = document.getElementById("fclk-reason-time");
        const reason = reasonEl ? reasonEl.value.trim() : "";
        const depTime = timeEl ? timeEl.value.trim() : "";

        if (!reason) {
            this._showToast("Please provide a reason.", "error");
            return;
        }

        try {
            const result = await rpc("/fusion_clock/submit_reason", {
                reason: reason,
                departure_time: depTime,
            });
            if (result.success) {
                const modal = document.getElementById("fclk-reason-modal");
                if (modal) modal.style.display = "none";
                this._showToast(result.message, "success");
                if (reasonEl) reasonEl.value = "";
                if (timeEl) timeEl.value = "";
            } else {
                this._showToast(result.error || "Failed to submit.", "error");
            }
        } catch (e) {
            this._showToast("Network error.", "error");
        }
    }

    async _submitLeave() {
        const dateEl = document.getElementById("fclk-leave-date");
        const reasonEl = document.getElementById("fclk-leave-reason");
        const leaveDate = dateEl ? dateEl.value : "";
        const reason = reasonEl ? reasonEl.value.trim() : "";

        if (!leaveDate || !reason) {
            this._showToast("Please provide both a date and reason.", "error");
            return;
        }

        try {
            const result = await rpc("/fusion_clock/request_leave", {
                leave_date: leaveDate,
                reason: reason,
            });
            if (result.success) {
                const modal = document.getElementById("fclk-leave-modal");
                if (modal) modal.style.display = "none";
                this._showToast(result.message, "success");
                if (dateEl) dateEl.value = "";
                if (reasonEl) reasonEl.value = "";
            } else {
                this._showToast(result.error || "Failed to submit.", "error");
            }
        } catch (e) {
            this._showToast("Network error.", "error");
        }
    }

    // =========================================================================
    // Sync on visibility change
    // =========================================================================

    async _syncOnVisibilityChange() {
        if (document.visibilityState !== "visible") return;

        try {
            const result = await rpc("/fusion_clock/get_status", {});
            if (result.error) return;

            if (result.is_checked_in && !this.isCheckedIn) {
                this.isCheckedIn = true;
                this.checkInTime = new Date(result.check_in + "Z");
                this._updateUIForClockIn({ location_name: result.location_name });
                this._startTimer();
                this._saveState();
            } else if (result.is_checked_in && this.isCheckedIn) {
                const serverTime = new Date(result.check_in + "Z");
                if (Math.abs(serverTime - this.checkInTime) > 5000) {
                    this.checkInTime = serverTime;
                    this._saveState();
                }
            } else if (!result.is_checked_in && this.isCheckedIn) {
                this.isCheckedIn = false;
                this._updateUIForClockOut({});
                this._stopTimer();
                this._clearState();
            }

            const todayEl = document.getElementById("fclk-today-hours");
            if (todayEl && result.today_hours !== undefined) {
                todayEl.textContent = result.today_hours.toFixed(1) + "h";
            }
            const weekEl = document.getElementById("fclk-week-hours");
            if (weekEl && result.week_hours !== undefined) {
                weekEl.textContent = result.week_hours.toFixed(1) + "h";
            }
        } catch {
            // Server unavailable (restarting) -- keep timer running from localStorage
        }
    }
}

registry.category("public.interactions").add("fusion_clock.portal", FusionClockPortal);
