'use strict';

import {Controller} from '@hotwired/stimulus';

const RETURNING_KEY = 'ferienpass.returningUser';
const METHOD_KEY = 'ferienpass.lastLoginMethod';

const TAB_ACTIVE = ['border-primary-500', 'dark:border-primary-400', 'text-primary-700', 'dark:text-primary-300'];
const TAB_INACTIVE = ['border-transparent', 'text-gray-500', 'dark:text-gray-300', 'hover:text-gray-700', 'hover:border-gray-300', 'dark:hover:text-gray-100'];

export default class extends Controller {
    static targets = ["loginTab", "registerTab", "loginPanel", "registerPanel", "cond"];
    static values = { hashNav: { type: Boolean, default: true } };

    declare readonly hashNavValue: boolean;

    declare readonly hasLoginTabTarget: boolean;
    declare readonly loginTabTarget: HTMLElement;
    declare readonly registerTabTarget: HTMLElement;
    declare readonly hasLoginPanelTarget: boolean;
    declare readonly loginPanelTarget: HTMLElement;
    declare readonly registerPanelTarget: HTMLElement;
    declare readonly condTargets: HTMLElement[];

    tab: 'login' | 'registration' = 'login';
    returning = false;
    lastMethod: string | null = null;
    revealPasskey = false;

    initialize() {
        try {
            this.returning = !!localStorage.getItem(RETURNING_KEY);
            this.lastMethod = localStorage.getItem(METHOD_KEY);
        } catch (e) {
        }

        this.tab = (this.hashNavValue && '#registrieren' === window.location.hash)
            ? 'registration'
            : (this.returning ? 'login' : 'registration');
    }

    connect() {
        this.applyTab();
        this.applyConds();
    }

    showLogin(event?: Event) {
        event?.preventDefault();
        this.setTab('login');
    }

    showRegister(event?: Event) {
        event?.preventDefault();
        this.setTab('registration');
    }

    setTab(tab: 'login' | 'registration') {
        this.tab = tab;
        if (this.hashNavValue) {
            // Update the hash without a navigation/scroll jump to "#".
            if ('registration' === tab && '#registrieren' !== location.hash) {
                history.replaceState(null, '', '#registrieren');
            }
            if ('login' === tab && '#registrieren' === location.hash) {
                history.replaceState(null, '', location.pathname + location.search);
            }
        }
        this.applyTab();
    }

    reveal() {
        this.revealPasskey = true;
        this.applyConds();
    }

    forget() {
        try {
            localStorage.removeItem(RETURNING_KEY);
            localStorage.removeItem(METHOD_KEY);
        } catch (e) {
        }
        this.returning = false;
        this.lastMethod = null;
        this.applyConds();
    }

    rememberPasskey() {
        try {
            localStorage.setItem(METHOD_KEY, 'passkey');
            localStorage.setItem(RETURNING_KEY, '1');
        } catch (e) {
        }
    }

    condTargetConnected(el: HTMLElement) {
        this.applyCond(el);
    }

    applyTab() {
        const isLogin = 'login' === this.tab;

        if (this.hasLoginTabTarget) {
            this.loginTabTarget.setAttribute('aria-selected', isLogin ? 'true' : 'false');
            this.registerTabTarget.setAttribute('aria-selected', isLogin ? 'false' : 'true');
            this.setTabClasses(this.loginTabTarget, isLogin);
            this.setTabClasses(this.registerTabTarget, !isLogin);
        }

        if (this.hasLoginPanelTarget) {
            this.loginPanelTarget.style.display = isLogin ? '' : 'none';
            this.registerPanelTarget.style.display = isLogin ? 'none' : '';
        }
    }

    private setTabClasses(el: HTMLElement, active: boolean) {
        TAB_ACTIVE.forEach((c) => el.classList.toggle(c, active));
        TAB_INACTIVE.forEach((c) => el.classList.toggle(c, !active));
    }

    applyConds() {
        this.condTargets.forEach((el) => this.applyCond(el));
    }

    private applyCond(el: HTMLElement) {
        el.style.display = this.evalCond(el.dataset.when) ? '' : 'none';
    }

    private evalCond(when?: string): boolean {
        const r = this.returning;
        const m = this.lastMethod;
        const rp = this.revealPasskey;

        switch (when) {
            case 'new':
                return !r;
            case 'returning':
                return r;
            case 'returning-password':
                return r && 'password' === m;
            case 'returning-not-password':
                return r && 'password' !== m;
            case 'last-password':
                return 'password' === m;
            case 'last-magic':
                return 'magicLink' === m;
            case 'passkey-visible':
                return ('password' !== m && 'magicLink' !== m) || rp;
            case 'or-visible':
                return (('password' !== m && 'magicLink' !== m) || rp) && 'passkey' !== m;
            case 'reveal-button':
                return 'password' === m && !rp;
            default:
                return true;
        }
    }
}
