import { Head } from '@inertiajs/react';
import axios from 'axios';
import { FormEvent, useEffect, useRef, useState } from 'react';

type Step = 'lookup' | 'pay' | 'waiting' | 'done';

// Swish only reports the outcome to our server, so the page asks us — not Swish —
// how the payment went. Give up after a few minutes so it does not poll forever.
const POLL_INTERVAL_MS = 2000;
const POLL_TIMEOUT_MS = 5 * 60 * 1000;

export default function Swish() {
    const [step, setStep] = useState<Step>('lookup');
    const [lanId, setLanId] = useState('');
    const [customerId, setCustomerId] = useState<number | null>(null);
    const [customerName, setCustomerName] = useState('');
    const [memberName, setMemberName] = useState<string | null>(null);
    const [amount, setAmount] = useState('');
    const [giveLeftover, setGiveLeftover] = useState(false);
    const [reference, setReference] = useState<string | null>(null);
    const [status, setStatus] = useState<string | null>(null);
    const [error, setError] = useState('');
    const [loading, setLoading] = useState(false);

    const timers = useRef<number[]>([]);

    const isMobile = /android|iphone|ipad|ipod/i.test(navigator.userAgent);

    // Stop polling when the page goes away
    useEffect(() => () => timers.current.forEach(clearTimeout), []);

    const reset = () => {
        timers.current.forEach(clearTimeout);
        timers.current = [];
        setStep('lookup');
        setLanId('');
        setAmount('');
        setGiveLeftover(false);
        setMemberName(null);
        setReference(null);
        setStatus(null);
        setError('');
    };

    // Server errors carry a message worth showing — a network failure does not
    const messageFrom = (e: unknown, fallback: string) => {
        if (axios.isAxiosError(e) && e.response?.status === 429) {
            return 'För många försök. Vänta en minut och prova igen.';
        }

        return (axios.isAxiosError(e) && e.response?.data?.message) || fallback;
    };

    const handleLookup = async (e: FormEvent) => {
        e.preventDefault();
        setError('');
        setLoading(true);
        try {
            const res = await axios.get('/api/swish/lookup', { params: { lan_id: lanId } });
            setCustomerId(res.data.customer_id);
            setCustomerName(res.data.name);
            setMemberName(res.data.member_name ?? null);
            setStep('pay');
        } catch (e) {
            setError(messageFrom(e, 'Hittade ingen deltagare med det LAN-id:t.'));
        } finally {
            setLoading(false);
        }
    };

    const pollStatus = (ref: string, startedAt: number) => {
        const timer = window.setTimeout(async () => {
            try {
                const res = await axios.get('/api/swish/status', { params: { reference: ref } });
                const current = res.data.status;

                if (current === 'PAID' || current === 'amount_mismatch') {
                    setStatus(current);
                    setStep('done');
                    return;
                }

                if (['DECLINED', 'ERROR', 'CANCELLED', 'failed'].includes(current)) {
                    setStatus(current);
                    setStep('done');
                    return;
                }
            } catch {
                // A failed poll is not a failed payment — keep trying until the timeout
            }

            if (Date.now() - startedAt < POLL_TIMEOUT_MS) {
                pollStatus(ref, startedAt);
            } else {
                setStatus('timeout');
                setStep('done');
            }
        }, POLL_INTERVAL_MS);

        timers.current.push(timer);
    };

    const handlePay = async (e: FormEvent) => {
        e.preventDefault();
        setError('');
        setLoading(true);
        try {
            const res = await axios.post('/api/swish/initiate', {
                customer_id: customerId,
                amount: parseInt(amount, 10),
                give_leftover: giveLeftover,
            });

            setReference(res.data.payment_reference);
            setStep('waiting');
            pollStatus(res.data.payment_reference, Date.now());
            window.location.href = res.data.swish_url;
        } catch (e) {
            setError(messageFrom(e, 'Något gick fel. Försök igen.'));
        } finally {
            setLoading(false);
        }
    };

    const outcome = () => {
        if (status === 'PAID') {
            return {
                title: '✓ Betalningen är klar!',
                text: `${amount} kr är inlagt på ${memberName ? `gruppen ${customerName}` : 'ditt'} saldo.`,
                tone: 'has-text-success',
            };
        }
        if (status === 'amount_mismatch') {
            return {
                title: 'Beloppet stämmer inte',
                text: 'Betalningen kom fram men beloppet matchade inte. Prata med en funktionär.',
                tone: 'has-text-danger',
            };
        }
        if (status === 'timeout') {
            return {
                title: 'Vi väntar fortfarande',
                text: 'Betalningen har inte bekräftats än. Kolla ditt saldo om en stund, eller prata med en funktionär.',
                tone: 'has-text-grey',
            };
        }
        return {
            title: 'Betalningen gick inte igenom',
            text: 'Inget har dragits. Du kan försöka igen.',
            tone: 'has-text-danger',
        };
    };

    return (
        <>
            <Head title="Betala in med Swish | vBytes LAN Kiosk" />
            <section className="section">
                <div className="container" style={{ maxWidth: 480 }}>
                    <h1 className="title is-3 has-text-centered mb-6">Betala in med Swish</h1>

                    {step === 'lookup' && (
                        <div className="box">
                            <p>Ange ditt LAN-id för att hitta ditt konto.</p>
                            <p className="mb-4"> Om du är med i en grupp kommer saldot skickas till din grupp.</p>
                            {!isMobile && (
                                <div className="notification is-warning is-light">
                                    Betalningen öppnas i Swish-appen, så den här sidan behöver köras i mobilen.
                                </div>
                            )}
                            <form onSubmit={handleLookup}>
                                <div className="field">
                                    <label className="label">LAN-id</label>
                                    <div className="control">
                                        <input
                                            className="input"
                                            type="number"
                                            min={1}
                                            value={lanId}
                                            onChange={e => setLanId(e.target.value)}
                                            required
                                            autoFocus
                                        />
                                    </div>
                                </div>
                                {error && <p className="help is-danger mb-3">{error}</p>}
                                <button
                                    className={`button is-link is-fullwidth ${loading ? 'is-loading' : ''}`}
                                    type="submit"
                                >
                                    Hitta mig
                                </button>
                            </form>
                        </div>
                    )}

                    {step === 'pay' && (
                        <div className="box">
                            <div className="notification is-success is-light mb-6">
                                <strong>{memberName ?? customerName}</strong> — stämmer det?
                                {memberName && (
                                    <p className="mt-1">Ingår i gruppen <strong>{customerName}</strong></p>
                                )}
                            </div>
                            <form onSubmit={handlePay}>
                                <div className="field">
                                    <label className="label">Belopp (kr)</label>
                                    <div className="control">
                                        <input
                                            className="input"
                                            type="number"
                                            min={1}
                                            value={amount}
                                            onChange={e => setAmount(e.target.value)}
                                            required
                                            autoFocus
                                        />
                                    </div>
                                </div>
                                <div className="field mt-6 mb-6">
                                    <label className="label">Ge överblivet saldo till vBytes?</label>
                                    <div className="control">
                                        <label className="radio mr-4">
                                            <input
                                                type="radio"
                                                className="accent-blue-600 mr-1"
                                                checked={giveLeftover === true}
                                                onChange={() => setGiveLeftover(true)}
                                            />
                                            Ja
                                        </label>
                                        <label className="radio">
                                            <input
                                                type="radio"
                                                className="accent-blue-600 mr-1"
                                                checked={giveLeftover === false}
                                                onChange={() => setGiveLeftover(false)}
                                            />
                                            Nej
                                        </label>
                                    </div>
                                </div>
                                {error && <p className="help is-danger mb-3">{error}</p>}
                                <div className="buttons mt-5">
                                    <button
                                        className={`button is-link is-fullwidth ${loading ? 'is-loading' : ''}`}
                                        type="submit"
                                    >
                                        Betala med Swish
                                    </button>
                                    <button
                                        className="button is-info is-outlined is-fullwidth"
                                        type="button"
                                        onClick={() => { setStep('lookup'); setMemberName(null); setError(''); }}
                                    >
                                        Fel person? Gå tillbaka
                                    </button>
                                </div>
                            </form>
                        </div>
                    )}

                    {step === 'waiting' && (
                        <div className="box has-text-centered">
                            <p className="is-size-4 mb-4">Väntar på Swish…</p>
                            <progress className="progress is-small is-link mb-5" max="100" />
                            <p className="has-text-grey mb-2">
                                Godkänn betalningen i Swish-appen. Den här sidan uppdaterar sig själv.
                            </p>
                            {reference && (
                                <p className="is-size-7 has-text-grey-light">Referens: {reference}</p>
                            )}
                        </div>
                    )}

                    {step === 'done' && (
                        <div className="box has-text-centered">
                            <p className={`is-size-4 mb-4 ${outcome().tone}`}>{outcome().title}</p>
                            <p className="has-text-grey mb-5">{outcome().text}</p>
                            {reference && (
                                <p className="is-size-7 has-text-grey-light mb-4">Referens: {reference}</p>
                            )}
                            <button className="button is-light" onClick={reset}>
                                Gör en ny betalning
                            </button>
                        </div>
                    )}
                </div>
            </section>
        </>
    );
}
