// Settings tab → License row (KL-38, Alpine conversion KL-126).
//
// Drives activate/deactivate against /api/license/* and gives the user
// a strong "you got what you paid for" signal: green stroke + checkmark
// + tier pill, then a celebratory toast and a page reload so locked
// tabs unlock instantly. The post-activate toast and reload now live in
// main.js's `license:activated` socket listener (KL-82) so the
// conductor:// deeplink and the manual-paste flow share one path.

import {pushToast} from './toasts.js';
import {trackEvent} from '../js/utils.js';

const TIER_LABELS = {starter: 'Starter', pro: 'Pro', venue: 'Venue'};

const OVERRIDE_HINTS = {
    dev_secret: 'Set via CONDUCTOR_DEV_SECRET — unset it and restart to revert.',
    env_license_key: 'Set via CONDUCTOR_LICENSE_KEY — unset it and restart to revert.',
    force_tier: 'Set via --force-tier — relaunch without that flag to revert.',
};

function storeDefinition() {
    return {
        // State machine — drives which sub-block is visible.
        state: 'loading',  // 'loading' | 'unlicensed' | 'active' | 'override'
        statusText: 'Loading…',

        // Active state
        tierLabel: 'Pro',
        keyMasked: '••••••••',
        fingerprintText: 'this machine',
        expiresFormatted: '—',
        showExpires: false,

        // Override state
        overrideTierLabel: 'Pro',
        overrideHint: 'Unset the override to see the real activation flow.',

        // Form state (unlicensed)
        inputValue: '',
        activateLabel: 'Activate',
        activateBusy: false,
        errorMessage: '',
        showError: false,

        // Deactivate
        deactivateLabel: 'Deactivate this device',
        deactivateBusy: false,

        showRestartHint: false,

        // Track tier across activations to detect Starter→Pro upgrades
        // for the restart hint.
        _lastTier: (window.CONDUCTOR_TIER || 'starter'),

        // Computed: drives the [data-state="..."] CSS selectors. Goes
        // to 'error' when an activation error is showing, else mirrors
        // `state` so the unlicensed sub-block stays visible during
        // error display (matches the original imperative behavior).
        get displayState() {
            return this.showError ? 'error' : this.state;
        },

        showUnlicensed() {
            this.state = 'unlicensed';
            this.statusText = 'Free tier — Starter';
            this.errorMessage = '';
            this.showError = false;
            this.showRestartHint = false;
            this.inputValue = '';
            this.activateBusy = false;
            this.activateLabel = 'Activate';
        },

        showActive(status) {
            this.state = 'active';
            const tier = (status.tier || 'pro').toLowerCase();
            const tierLabel = TIER_LABELS[tier] || tier;
            this.statusText = `${tierLabel} license active`;
            this.tierLabel = tierLabel;

            // The backend never sends the full key in the status payload —
            // and that's by design — so we render a generic mask.
            this.keyMasked = '••••••••' + (status.fingerprint
                ? ' (' + status.fingerprint.slice(0, 6) + '…)'
                : '');
            this.fingerprintText = status.fingerprint
                ? `this machine (${status.fingerprint})`
                : 'this machine';

            const expires = status.subscription_expires_at;
            if (expires) {
                try {
                    const dt = new Date(expires);
                    this.expiresFormatted = dt.toLocaleDateString(undefined, {
                        year: 'numeric', month: 'short', day: 'numeric',
                    });
                    this.showExpires = true;
                } catch (_) {
                    this.showExpires = false;
                }
            } else {
                this.showExpires = false;
            }
            this.showError = false;
        },

        showOverride(status) {
            this.state = 'override';
            const tier = (status.runtime_tier || 'pro').toLowerCase();
            const tierLabel = TIER_LABELS[tier] || tier;
            this.statusText = `Override — ${tierLabel}`;
            this.overrideTierLabel = tierLabel;
            this.overrideHint = OVERRIDE_HINTS[status.override_reason]
                || 'Override active — relaunch without it to revert.';
            this.showRestartHint = false;
        },

        showErrorState(message) {
            // Don't change state — keep unlicensed sub-block visible so
            // the user can edit the input and retry. displayState getter
            // returns 'error' so the [data-state="error"] CSS still
            // turns the border red.
            this.errorMessage = message || 'Activation failed.';
            this.showError = true;
            this.activateBusy = false;
            this.activateLabel = 'Activate';
        },

        async loadStatus() {
            try {
                const resp = await fetch('/api/license/status');
                const data = await resp.json();
                if (data.override_active) {
                    this.showOverride(data);
                } else if (data.licensed) {
                    this.showActive(data);
                } else {
                    this.showUnlicensed();
                }
            } catch (_) {
                // Network hiccup at load — treat as unlicensed; the user
                // can still try to activate, which will surface a real
                // error.
                this.showUnlicensed();
            }
        },

        async activate() {
            const key = (this.inputValue || '').trim();
            if (!key) {
                this.showErrorState('Paste a license key first.');
                document.getElementById('license-key-input')?.focus();
                return;
            }

            this.showError = false;
            this.errorMessage = '';
            this.activateBusy = true;
            this.activateLabel = 'Activating…';

            try {
                const resp = await fetch('/api/license/activate', {
                    method: 'POST',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify({license_key: key}),
                });
                const data = await resp.json();
                if (!resp.ok || !data.ok) {
                    this.showErrorState(data.error || 'Activation failed.');
                    trackEvent('checkout.activated', {
                        success: false,
                        error: (data.error || 'unknown').slice(0, 120),
                    });
                    return;
                }

                const newTier = (data.tier || 'pro').toLowerCase();
                const upgradedFromStarter = (this._lastTier === 'starter');

                // Refresh status from the server so the masked key + expiry
                // come from the canonical cache rather than guesswork.
                try {
                    const sResp = await fetch('/api/license/status');
                    const sData = await sResp.json();
                    if (sData.licensed) this.showActive(sData);
                } catch (_) {
                    this.showActive({tier: newTier});
                }

                // Hardware-bound subsystems (DMX, sACN) bind at startup,
                // so a starter→pro/venue activation usually warrants a
                // restart hint. Skip if they were already on a paid tier.
                if (upgradedFromStarter && (newTier === 'pro' || newTier === 'venue')) {
                    this.showRestartHint = true;
                }

                trackEvent('checkout.activated', {
                    success: true,
                    tier: newTier,
                    from_tier: this._lastTier,
                });
            } catch (e) {
                this.showErrorState('Network error. Check your connection and try again.');
                trackEvent('checkout.activated', {
                    success: false,
                    error: 'network_error',
                });
            }
        },

        async deactivate() {
            if (!confirm(
                'Deactivate this device?\n\n'
                + 'This frees up an activation slot on your license. '
                + 'You can re-activate any time by pasting the key again.'
            )) return;

            this.deactivateBusy = true;
            this.deactivateLabel = 'Deactivating…';

            try {
                const resp = await fetch('/api/license/deactivate', {method: 'POST'});
                const data = await resp.json();
                if (!resp.ok || !data.ok) {
                    pushToast({
                        key: 'license-deactivate-failed',
                        level: 'error',
                        title: 'Deactivation failed',
                        detail: data.message || 'Try again or restart Conductør.',
                    });
                    this.deactivateBusy = false;
                    this.deactivateLabel = 'Deactivate this device';
                    return;
                }
                // Same reload trick — server re-renders as Starter.
                pushToast({
                    key: 'license-deactivated',
                    level: 'info',
                    title: 'License deactivated',
                    detail: 'Refreshing…',
                    dismissible: false,
                });
                setTimeout(() => window.location.reload(), 1200);
            } catch (_) {
                pushToast({
                    key: 'license-deactivate-failed',
                    level: 'error',
                    title: 'Network error',
                    detail: 'Could not reach the deactivation endpoint.',
                });
                this.deactivateBusy = false;
                this.deactivateLabel = 'Deactivate this device';
            }
        },
    };
}

function ensureStore() {
    if (!window.Alpine) return null;
    if (!window.Alpine.store('license')) {
        window.Alpine.store('license', storeDefinition());
    }
    return window.Alpine.store('license');
}

if (window.Alpine) {
    ensureStore();
} else {
    document.addEventListener('alpine:init', ensureStore);
}

export function initLicense() {
    const row = document.getElementById('license-row');
    if (!row) return;

    let store = ensureStore();
    if (!store) {
        document.addEventListener('alpine:init', () => {
            ensureStore()?.loadStatus();
        }, {once: true});
        return;
    }
    store.loadStatus();
}
