<script lang="ts">
    import { goto } from '$app/navigation';
    import { changePassword } from '$lib/api/auth';
    import { ApiError } from '$lib/api/client';
    import type { ReaderMode, ReaderPageGap } from '$lib/api/preferences';
    import { preferences } from '$lib/preferences.svelte';
    import { session } from '$lib/session.svelte';
    import { theme, type Theme } from '$lib/theme.svelte';
    import Monitor from '@lucide/svelte/icons/monitor';
    import Sun from '@lucide/svelte/icons/sun';
    import Moon from '@lucide/svelte/icons/moon';
    import FileText from '@lucide/svelte/icons/file-text';
    import ScrollText from '@lucide/svelte/icons/scroll-text';

    const READER_MODES: { value: ReaderMode; label: string }[] = [
        { value: 'single', label: 'Single page' },
        { value: 'continuous', label: 'Continuous (scroll)' }
    ];
    const READER_GAPS: { value: ReaderPageGap; label: string }[] = [
        { value: 'none', label: 'None' },
        { value: 'small', label: 'Small' },
        { value: 'medium', label: 'Medium' },
        { value: 'large', label: 'Large' }
    ];

    function setTheme(next: Theme) {
        theme.set(next);
    }

    let currentPassword = $state('');
    let newPassword = $state('');
    let confirmPassword = $state('');
    let submitting = $state(false);
    let success = $state<string | null>(null);
    let error: string | null = $state(null);

    const passwordsMatch = $derived(
        newPassword.length > 0 && newPassword === confirmPassword
    );
    const canSubmit = $derived(
        Boolean(session.user) &&
            currentPassword.length > 0 &&
            newPassword.length >= 8 &&
            passwordsMatch &&
            !submitting
    );

    async function submit(e: SubmitEvent) {
        e.preventDefault();
        if (!canSubmit) return;
        submitting = true;
        success = null;
        error = null;
        try {
            await changePassword({
                current_password: currentPassword,
                new_password: newPassword
            });
            success = 'Password updated. Other devices have been signed out.';
            currentPassword = '';
            newPassword = '';
            confirmPassword = '';
        } catch (e) {
            if (e instanceof ApiError && e.status === 401 && !session.user) {
                // The CurrentUser extractor rejected us — session must
                // have been wiped externally. Bounce to login.
                await goto('/login');
                return;
            }
            error = e instanceof Error ? e.message : String(e);
        } finally {
            submitting = false;
        }
    }
</script>

<svelte:head>
    <title>Settings — Mangalord</title>
</svelte:head>

<h1>Settings</h1>

<section class="card" aria-label="Appearance">
    <h2>Appearance</h2>
    <fieldset class="theme-picker">
        <legend>Theme</legend>
        <label class="theme-option" class:selected={theme.value === 'system'}>
            <input
                type="radio"
                name="theme"
                value="system"
                checked={theme.value === 'system'}
                onchange={() => setTheme('system')}
                data-testid="theme-radio-system"
            />
            <Monitor size={18} aria-hidden="true" />
            <span>System</span>
        </label>
        <label class="theme-option" class:selected={theme.value === 'light'}>
            <input
                type="radio"
                name="theme"
                value="light"
                checked={theme.value === 'light'}
                onchange={() => setTheme('light')}
                data-testid="theme-radio-light"
            />
            <Sun size={18} aria-hidden="true" />
            <span>Light</span>
        </label>
        <label class="theme-option" class:selected={theme.value === 'dark'}>
            <input
                type="radio"
                name="theme"
                value="dark"
                checked={theme.value === 'dark'}
                onchange={() => setTheme('dark')}
                data-testid="theme-radio-dark"
            />
            <Moon size={18} aria-hidden="true" />
            <span>Dark</span>
        </label>
    </fieldset>
</section>

<section class="card" aria-label="Reader">
    <h2>Reader</h2>
    {#if !session.user}
        <p class="hint" data-testid="reader-prefs-guest-hint">
            Sign in to sync these settings across devices. Until then they live in this browser.
        </p>
    {/if}
    <fieldset class="theme-picker">
        <legend>Layout</legend>
        {#each READER_MODES as opt (opt.value)}
            <label class="theme-option" class:selected={preferences.readerMode === opt.value}>
                <input
                    type="radio"
                    name="reader-mode"
                    value={opt.value}
                    checked={preferences.readerMode === opt.value}
                    onchange={() => preferences.setMode(opt.value)}
                    data-testid={`reader-mode-radio-${opt.value}`}
                />
                {#if opt.value === 'single'}
                    <FileText size={18} aria-hidden="true" />
                {:else}
                    <ScrollText size={18} aria-hidden="true" />
                {/if}
                <span>{opt.label}</span>
            </label>
        {/each}
    </fieldset>

    {#if preferences.readerMode === 'continuous'}
        <fieldset class="theme-picker gap-picker">
            <legend>Page gap</legend>
            {#each READER_GAPS as opt (opt.value)}
                <label class="theme-option" class:selected={preferences.readerPageGap === opt.value}>
                    <input
                        type="radio"
                        name="reader-gap"
                        value={opt.value}
                        checked={preferences.readerPageGap === opt.value}
                        onchange={() => preferences.setGap(opt.value)}
                        data-testid={`reader-gap-radio-${opt.value}`}
                    />
                    <span>{opt.label}</span>
                </label>
            {/each}
        </fieldset>
    {/if}
</section>

{#if !session.loaded}
    <p class="status" data-testid="settings-loading">Loading…</p>
{:else if !session.user}
    <p class="status" data-testid="settings-signin">
        <a href="/login">Sign in</a> to change your password.
    </p>
{:else}
    <section class="card">
        <h2>Change password</h2>
        <p class="hint">
            Changing your password signs out every other device using this account.
            Bot API tokens keep working — revoke them individually from the bot-token
            list if you want to invalidate them too.
        </p>
        <form onsubmit={submit} action="javascript:void(0)" data-testid="password-form">
            <label class="form-field">
                <span>Current password</span>
                <input
                    type="password"
                    bind:value={currentPassword}
                    autocomplete="current-password"
                    required
                    data-testid="current-password"
                />
            </label>
            <label class="form-field">
                <span>New password</span>
                <input
                    type="password"
                    bind:value={newPassword}
                    autocomplete="new-password"
                    minlength="8"
                    required
                    data-testid="new-password"
                />
            </label>
            <label class="form-field">
                <span>Confirm new password</span>
                <input
                    type="password"
                    bind:value={confirmPassword}
                    autocomplete="new-password"
                    minlength="8"
                    required
                    data-testid="confirm-password"
                />
                {#if confirmPassword.length > 0 && !passwordsMatch}
                    <span class="field-error" role="alert" data-testid="mismatch">
                        Passwords don't match.
                    </span>
                {/if}
            </label>
            <button
                class="primary"
                type="submit"
                disabled={!canSubmit}
                data-testid="password-submit"
            >
                {submitting ? 'Updating…' : 'Update password'}
            </button>
            {#if success}
                <p class="success" data-testid="password-success">{success}</p>
            {/if}
            {#if error}
                <p role="alert" class="form-error" data-testid="password-error">{error}</p>
            {/if}
        </form>
    </section>
{/if}

<style>
    .status {
        color: var(--text-muted);
    }

    .card {
        background: var(--surface);
        border: 1px solid var(--border);
        border-radius: var(--radius-md);
        padding: var(--space-4);
        max-width: 32rem;
        margin-bottom: var(--space-4);
    }

    .hint {
        color: var(--text-muted);
        font-size: var(--font-sm);
    }

    form {
        display: flex;
        flex-direction: column;
        gap: var(--space-3);
    }

    .primary {
        background: var(--primary);
        color: var(--primary-contrast);
        border-color: var(--primary);
        margin-top: var(--space-1);
        align-self: flex-start;
    }

    .primary:hover:not(:disabled) {
        background: var(--primary-hover);
        border-color: var(--primary-hover);
    }

    .field-error {
        color: var(--danger);
        font-size: var(--font-sm);
    }

    .form-error {
        color: var(--danger);
    }

    .success {
        color: var(--success);
    }

    .theme-picker {
        display: flex;
        flex-wrap: wrap;
        gap: var(--space-2);
        border: none;
        padding: 0;
        margin: 0;
    }

    .gap-picker {
        margin-top: var(--space-3);
    }

    .theme-picker legend {
        font-size: var(--font-sm);
        color: var(--text);
        padding: 0;
        margin-bottom: var(--space-2);
    }

    .theme-option {
        display: inline-flex;
        align-items: center;
        gap: var(--space-2);
        padding: var(--space-2) var(--space-3);
        border: 1px solid var(--border-strong);
        border-radius: var(--radius-md);
        background: var(--surface);
        color: var(--text);
        font-size: var(--font-sm);
        cursor: pointer;
        transition:
            background var(--transition),
            border-color var(--transition);
    }

    .theme-option:hover {
        background: var(--surface-elevated);
    }

    .theme-option input[type='radio'] {
        position: absolute;
        opacity: 0;
        pointer-events: none;
        width: 0;
        height: 0;
    }

    .theme-option.selected {
        background: var(--primary-soft-bg);
        border-color: var(--primary);
        color: var(--text);
    }

    .theme-option:has(input:focus-visible) {
        outline: 2px solid var(--focus-ring);
        outline-offset: 2px;
    }
</style>
