import { useMemo, useState } from "react";

import { BUTTON_CAPABILITIES } from "@/constants/controls";
import { Button } from "@/components/common/Button";
import { Panel } from "@/components/common/Panel";
import { Select } from "@/components/inputs/Select";
import { TextField } from "@/components/inputs/TextField";
import { UnsavedChangesBar } from "@/components/feedback/UnsavedChangesBar";
import { PageShell } from "@/components/layout/PageShell";
import { ControllerDiagram, type ControllerView } from "@/components/controller/ControllerDiagram";
import { useControllerStore } from "@/stores/controllerStore";
import { useProfileStore } from "@/stores/profileStore";
import { useUIStore } from "@/stores/uiStore";
import type { ActionMode, ButtonMapping as ButtonMappingType, MappingTarget } from "@/types/profile";

/** Buttons that must always stay functional so the user can never lose control of the app or controller. */
const PROTECTED_CONTROL_IDS = new Set(["guide"]);

const MODE_OPTIONS: { value: ActionMode; label: string }[] = [
  { value: "normal", label: "Normal" },
  { value: "turbo", label: "Turbo" },
  { value: "toggle", label: "Toggle" },
  { value: "hold", label: "Hold" },
  { value: "longPress", label: "Long Press" },
  { value: "doubleTap", label: "Double Tap" },
];

type TargetKind = MappingTarget["kind"];

const TARGET_KIND_OPTIONS: { value: TargetKind; label: string }[] = [
  { value: "button", label: "Button" },
  { value: "key", label: "Keyboard Key" },
  { value: "mouseButton", label: "Mouse Button" },
  { value: "disabled", label: "Disabled" },
];

function defaultMappingFor(controlId: string): ButtonMappingType {
  return { target: { kind: "button", button: controlId }, mode: "normal" };
}

function isRemapped(controlId: string, mapping: ButtonMappingType | undefined): boolean {
  if (!mapping) return false;
  return !(mapping.target.kind === "button" && mapping.target.button === controlId) || mapping.mode !== "normal";
}

export function ButtonMapping() {
  const [view, setView] = useState<ControllerView>("front");
  const [selectedId, setSelectedId] = useState<string | null>(null);

  const liveState = useControllerStore((s) => s.liveState);
  const draftProfile = useProfileStore((s) => s.draftProfile);
  const updateDraft = useProfileStore((s) => s.updateDraft);
  const pushToast = useUIStore((s) => s.pushToast);

  const remappedIds = useMemo(() => {
    if (!draftProfile) return new Set<string>();
    const ids = Object.entries(draftProfile.buttonMappings)
      .filter(([id, mapping]) => isRemapped(id, mapping))
      .map(([id]) => id);
    return new Set(ids);
  }, [draftProfile]);

  if (!draftProfile) {
    return (
      <PageShell title="Button Mapping" description="Loading profile...">
        <div />
      </PageShell>
    );
  }

  const selectedButton = selectedId ? BUTTON_CAPABILITIES.find((b) => b.id === selectedId) : null;
  const mapping = selectedId ? draftProfile.buttonMappings[selectedId] ?? defaultMappingFor(selectedId) : null;

  function updateMapping(controlId: string, next: ButtonMappingType) {
    if (PROTECTED_CONTROL_IDS.has(controlId) && next.target.kind === "disabled") {
      pushToast("The Guide button can't be disabled — it's kept available so you can't lock yourself out.", "warning");
      return;
    }
    updateDraft((draft) => ({
      ...draft,
      buttonMappings: { ...draft.buttonMappings, [controlId]: next },
    }));
  }

  return (
    <PageShell title="Button Mapping" description="Click any control on the diagram to remap it.">
      <UnsavedChangesBar />

      <div className="grid grid-cols-[1.3fr_1fr] gap-5">
        <Panel
          title={view === "front" ? "Front view" : "Rear view"}
          actions={
            <div className="flex gap-1.5">
              <Button size="sm" variant={view === "front" ? "primary" : "secondary"} onClick={() => setView("front")}>
                Front
              </Button>
              <Button size="sm" variant={view === "rear" ? "primary" : "secondary"} onClick={() => setView("rear")}>
                Rear
              </Button>
            </div>
          }
        >
          <div className="mx-auto aspect-[480/280] max-w-xl">
            <ControllerDiagram
              view={view}
              buttons={liveState?.buttons ?? {}}
              axes={liveState?.axes ?? {}}
              selectedId={selectedId}
              remappedIds={remappedIds}
              onSelect={setSelectedId}
            />
          </div>
        </Panel>

        <Panel title={selectedButton ? `Mapping: ${selectedButton.label}` : "Select a control"}>
          {!selectedId || !mapping ? (
            <p className="text-sm text-fg-subtle">
              Click a button, D-pad direction, shoulder button, stick click, or paddle on the diagram to configure it.
            </p>
          ) : (
            <div className="flex flex-col gap-4">
              <Select
                label="Action"
                value={mapping.target.kind}
                options={TARGET_KIND_OPTIONS}
                onChange={(kind) => {
                  const target: MappingTarget =
                    kind === "button"
                      ? { kind: "button", button: selectedId }
                      : kind === "key"
                        ? { kind: "key", key: "" }
                        : kind === "mouseButton"
                          ? { kind: "mouseButton", button: "left" }
                          : { kind: "disabled" };
                  updateMapping(selectedId, { ...mapping, target });
                }}
              />

              {mapping.target.kind === "button" && (
                <Select
                  label="Remap to button"
                  value={mapping.target.button}
                  options={BUTTON_CAPABILITIES.map((b) => ({ value: b.id, label: b.label }))}
                  onChange={(button) => updateMapping(selectedId, { ...mapping, target: { kind: "button", button } })}
                />
              )}

              {mapping.target.kind === "key" && (
                <TextField
                  label="Key name"
                  placeholder="e.g. Space, KeyW, Enter"
                  value={mapping.target.key}
                  onChange={(e) =>
                    updateMapping(selectedId, { ...mapping, target: { kind: "key", key: e.currentTarget.value } })
                  }
                />
              )}

              {mapping.target.kind === "mouseButton" && (
                <Select
                  label="Mouse button"
                  value={mapping.target.button}
                  options={[
                    { value: "left", label: "Left" },
                    { value: "right", label: "Right" },
                    { value: "middle", label: "Middle" },
                  ]}
                  onChange={(button) =>
                    updateMapping(selectedId, { ...mapping, target: { kind: "mouseButton", button } })
                  }
                />
              )}

              <Select
                label="Mode"
                value={mapping.mode}
                options={MODE_OPTIONS}
                onChange={(mode) => updateMapping(selectedId, { ...mapping, mode })}
              />

              {mapping.mode === "turbo" && (
                <TextField
                  label="Turbo rate (Hz)"
                  type="number"
                  min={1}
                  max={30}
                  value={mapping.turboRateHz ?? 10}
                  onChange={(e) => updateMapping(selectedId, { ...mapping, turboRateHz: Number(e.currentTarget.value) })}
                />
              )}

              {mapping.mode === "longPress" && (
                <TextField
                  label="Long-press threshold (ms)"
                  type="number"
                  min={100}
                  max={3000}
                  value={mapping.longPressMs ?? 500}
                  onChange={(e) => updateMapping(selectedId, { ...mapping, longPressMs: Number(e.currentTarget.value) })}
                />
              )}

              {mapping.mode === "doubleTap" && (
                <TextField
                  label="Double-tap window (ms)"
                  type="number"
                  min={100}
                  max={1000}
                  value={mapping.doubleTapWindowMs ?? 300}
                  onChange={(e) =>
                    updateMapping(selectedId, { ...mapping, doubleTapWindowMs: Number(e.currentTarget.value) })
                  }
                />
              )}

              <Button
                variant="ghost"
                onClick={() => updateMapping(selectedId, defaultMappingFor(selectedId))}
              >
                Reset this control
              </Button>
            </div>
          )}
        </Panel>
      </div>
    </PageShell>
  );
}
