import React, { createContext, useCallback, useContext, useMemo, useState } from "react";
import { createPortal } from "react-dom";

export function classNames(...parts: Array<string | false | null | undefined>) {
    return parts.filter(Boolean).join(" ");
}

type NinjaSfxType = "save" | "delete" | "upload";

let ninjaAudioCtx: AudioContext | null = null;

function getAudioCtx() {
    if (typeof window === "undefined") return null;
    const w = window as any;
    const Ctx = (w.AudioContext || w.webkitAudioContext) as typeof AudioContext | undefined;
    if (!Ctx) return null;
    if (!ninjaAudioCtx) ninjaAudioCtx = new Ctx();
    return ninjaAudioCtx;
}

export function playNinjaSfx(type: NinjaSfxType) {
    const ctx = getAudioCtx();
    if (!ctx) return;

    const t0 = ctx.currentTime;
    void ctx.resume().catch(() => {});

    const master = ctx.createGain();
    master.gain.setValueAtTime(0.00001, t0);
    master.gain.linearRampToValueAtTime(0.035, t0 + 0.01);
    master.gain.exponentialRampToValueAtTime(0.00001, t0 + 0.18);
    master.connect(ctx.destination);

    const osc = ctx.createOscillator();
    const gain = ctx.createGain();
    gain.gain.setValueAtTime(0.00001, t0);
    gain.gain.linearRampToValueAtTime(1, t0 + 0.01);
    gain.gain.exponentialRampToValueAtTime(0.00001, t0 + 0.18);

    osc.connect(gain);
    gain.connect(master);

    if (type === "save") {
        osc.type = "triangle";
        osc.frequency.setValueAtTime(440, t0);
        osc.frequency.exponentialRampToValueAtTime(720, t0 + 0.09);
    } else if (type === "delete") {
        osc.type = "sawtooth";
        osc.frequency.setValueAtTime(160, t0);
        osc.frequency.exponentialRampToValueAtTime(90, t0 + 0.12);
        master.gain.setValueAtTime(0.00001, t0);
        master.gain.linearRampToValueAtTime(0.04, t0 + 0.01);
        master.gain.exponentialRampToValueAtTime(0.00001, t0 + 0.22);
    } else {
        osc.type = "square";
        osc.frequency.setValueAtTime(980, t0);
        osc.frequency.exponentialRampToValueAtTime(520, t0 + 0.12);
        master.gain.setValueAtTime(0.00001, t0);
        master.gain.linearRampToValueAtTime(0.03, t0 + 0.008);
        master.gain.exponentialRampToValueAtTime(0.00001, t0 + 0.14);
    }

    osc.start(t0);
    osc.stop(t0 + 0.2);
}

export function useNinjaSfx() {
    return useMemo(() => ({ play: playNinjaSfx }), []);
}

type ToastType = "success" | "error" | "info";
type ToastItem = { id: string; type: ToastType; message: string };

type ToastContextValue = {
    toast: (type: ToastType, message: string) => void;
};

const ToastContext = createContext<ToastContextValue | null>(null);

export function useToast() {
    const ctx = useContext(ToastContext);
    if (!ctx) throw new Error("ToastProvider missing");
    return ctx;
}

export function ToastProvider({ children }: { children: React.ReactNode }) {
    const [items, setItems] = useState<ToastItem[]>([]);

    const toast = useCallback((type: ToastType, message: string) => {
        const id = `${Date.now()}-${Math.random().toString(16).slice(2)}`;
        const item: ToastItem = { id, type, message };
        setItems((prev) => [item, ...prev].slice(0, 4));
        window.setTimeout(() => {
            setItems((prev) => prev.filter((t) => t.id !== id));
        }, 3200);
    }, []);

    const value = useMemo(() => ({ toast }), [toast]);

    return (
        <ToastContext.Provider value={value}>
            {children}
            {typeof document !== "undefined"
                ? createPortal(
                      <div className="pointer-events-none fixed right-4 top-4 z-[9999] space-y-2">
                          {items.map((t) => {
                              const styles =
                                  t.type === "success"
                                      ? "border-emerald-500/30 bg-emerald-500/10 text-emerald-100"
                                      : t.type === "error"
                                        ? "border-rose-500/30 bg-rose-500/10 text-rose-100"
                                        : "border-white/10 bg-white/5 text-gray-100";

                              return (
                                  <div
                                      key={t.id}
                                      className={classNames(
                                          "pointer-events-auto w-[340px] max-w-[calc(100vw-2rem)] rounded-2xl border px-4 py-3 text-sm font-semibold shadow-[0_20px_60px_-45px_rgba(0,0,0,0.95)] backdrop-blur transition duration-300",
                                          styles,
                                      )}
                                  >
                                      {t.message}
                                  </div>
                              );
                          })}
                      </div>,
                      document.body,
                  )
                : null}
        </ToastContext.Provider>
    );
}

export function Button({
    children,
    variant = "primary",
    className,
    tip,
    ...props
}: React.ButtonHTMLAttributes<HTMLButtonElement> & {
    variant?: "primary" | "secondary" | "danger";
    tip?: string;
}) {
    const base =
        "ninja-btn inline-flex items-center justify-center rounded-xl px-4 py-2 text-sm font-semibold shadow-sm transition duration-300 focus:outline-none focus:ring-2 focus:ring-fuchsia-500/60 disabled:cursor-not-allowed disabled:opacity-60";
    const style =
        variant === "primary"
            ? "bg-gradient-to-r from-[#FFD700] to-fuchsia-600 text-black shadow-fuchsia-600/10 hover:from-[#ffdf3a] hover:to-fuchsia-500"
            : variant === "danger"
              ? "bg-rose-600/80 text-white hover:bg-rose-600"
              : "border border-white/10 bg-white/5 text-gray-100 hover:bg-white/10";

    return (
        <button
            {...props}
            data-tip={tip}
            className={classNames(base, style, tip ? "ninja-tip" : "", className)}
        >
            {children}
        </button>
    );
}

export function TextInput({
    label,
    error,
    className,
    ...props
}: React.InputHTMLAttributes<HTMLInputElement> & {
    label?: string;
    error?: string | null;
}) {
    return (
        <label className={classNames("block", className)}>
            {label ? (
                <div className="mb-1 text-xs font-semibold uppercase tracking-[0.14em] text-gray-300">
                    {label}
                </div>
            ) : null}
            <input
                {...props}
                className={classNames(
                    "block w-full rounded-xl border border-white/10 bg-white/[0.03] px-3 py-2 text-sm font-semibold text-gray-100 placeholder:text-gray-500 shadow-sm outline-none transition duration-300 focus:border-fuchsia-500 focus:ring-2 focus:ring-fuchsia-500/40",
                    error ? "border-rose-500/50 focus:border-rose-400 focus:ring-rose-500/30" : "",
                )}
            />
            {error ? <div className="mt-1 text-xs font-semibold text-rose-200">{error}</div> : null}
        </label>
    );
}

export function TextArea({
    label,
    error,
    className,
    ...props
}: React.TextareaHTMLAttributes<HTMLTextAreaElement> & {
    label?: string;
    error?: string | null;
}) {
    return (
        <label className={classNames("block", className)}>
            {label ? (
                <div className="mb-1 text-xs font-semibold uppercase tracking-[0.14em] text-gray-300">
                    {label}
                </div>
            ) : null}
            <textarea
                {...props}
                className={classNames(
                    "block w-full rounded-xl border border-white/10 bg-white/[0.03] px-3 py-2 text-sm font-semibold text-gray-100 placeholder:text-gray-500 shadow-sm outline-none transition duration-300 focus:border-fuchsia-500 focus:ring-2 focus:ring-fuchsia-500/40",
                    error ? "border-rose-500/50 focus:border-rose-400 focus:ring-rose-500/30" : "",
                )}
            />
            {error ? <div className="mt-1 text-xs font-semibold text-rose-200">{error}</div> : null}
        </label>
    );
}

export function Select({
    label,
    className,
    ...props
}: React.SelectHTMLAttributes<HTMLSelectElement> & {
    label?: string;
}) {
    return (
        <label className={classNames("block", className)}>
            {label ? (
                <div className="mb-1 text-xs font-semibold uppercase tracking-[0.14em] text-gray-300">
                    {label}
                </div>
            ) : null}
            <select
                {...props}
                className={classNames(
                    "block w-full rounded-xl border border-white/10 bg-white/[0.03] px-3 py-2 text-sm font-semibold text-gray-100 shadow-sm outline-none transition duration-300 focus:border-fuchsia-500 focus:ring-2 focus:ring-fuchsia-500/40",
                )}
            />
        </label>
    );
}

export function Modal({
    open,
    title,
    onClose,
    children,
    footer,
    widthClassName = "max-w-3xl",
}: {
    open: boolean;
    title: string;
    onClose: () => void;
    children: React.ReactNode;
    footer?: React.ReactNode;
    widthClassName?: string;
}) {
    if (!open) return null;

    if (typeof document === "undefined") return null;

    return createPortal(
        <div className="fixed inset-0 z-[9998]">
            <div
                className="absolute inset-0 bg-black/70 backdrop-blur-sm"
                onClick={onClose}
            />
            <div className="absolute inset-0 overflow-y-auto p-4">
                <div
                    className={classNames(
                        "mx-auto mt-10 rounded-2xl border border-white/10 bg-[#070914]/95 shadow-[0_40px_120px_-80px_rgba(0,0,0,0.95)] ring-1 ring-black/30 backdrop-blur",
                        widthClassName,
                    )}
                >
                    <div className="flex items-center justify-between gap-3 border-b border-white/10 px-5 py-4">
                        <div className="text-sm font-semibold text-white">
                            <span className="text-[#FFD700]">◆</span>{" "}
                            {title}
                        </div>
                        <button
                            type="button"
                            onClick={onClose}
                            className="inline-flex rounded-lg border border-white/10 bg-white/5 px-2 py-1 text-xs font-semibold text-gray-100 transition duration-300 hover:bg-white/10"
                        >
                            Tutup
                        </button>
                    </div>
                    <div className="px-5 py-4">{children}</div>
                    {footer ? (
                        <div className="flex items-center justify-end gap-2 border-t border-white/10 px-5 py-4">
                            {footer}
                        </div>
                    ) : null}
                </div>
            </div>
        </div>,
        document.body,
    );
}

export function Pagination({
    page,
    lastPage,
    onPage,
}: {
    page: number;
    lastPage: number;
    onPage: (page: number) => void;
}) {
    const canPrev = page > 1;
    const canNext = page < lastPage;
    const pages = Array.from({ length: Math.min(lastPage, 7) }, (_, i) => {
        const start = Math.max(1, Math.min(page - 3, lastPage - 6));
        return start + i;
    }).filter((p) => p >= 1 && p <= lastPage);

    return (
        <div className="flex flex-wrap items-center justify-between gap-3">
            <div className="text-xs font-semibold text-gray-300/80">
                Page <span className="text-white">{page}</span> /{" "}
                <span className="text-white">{lastPage}</span>
            </div>
            <div className="flex items-center gap-2">
                <Button
                    type="button"
                    variant="secondary"
                    disabled={!canPrev}
                    onClick={() => onPage(page - 1)}
                >
                    Prev
                </Button>
                <div className="flex items-center gap-1">
                    {pages.map((p) => (
                        <button
                            key={p}
                            type="button"
                            onClick={() => onPage(p)}
                            className={classNames(
                                "h-9 w-9 rounded-xl border text-sm font-semibold transition duration-300",
                                p === page
                                    ? "border-[#FFD700]/40 bg-[#FFD700]/15 text-[#FFD700]"
                                    : "border-white/10 bg-white/5 text-gray-100 hover:bg-white/10",
                            )}
                        >
                            {p}
                        </button>
                    ))}
                </div>
                <Button
                    type="button"
                    variant="secondary"
                    disabled={!canNext}
                    onClick={() => onPage(page + 1)}
                >
                    Next
                </Button>
            </div>
        </div>
    );
}
