import { useRef, useState } from "react";
import type { JsonObject } from "../editorCore";
import type { RecordEditorBaseContext } from "./editorContexts";

type RecordEditorBasePanelProps = {
  ctx: RecordEditorBaseContext;
};

export default function RecordEditorBasePanel({ ctx }: RecordEditorBasePanelProps) {
  const SPRITE_CANVAS_SIZE = 16;
  const {
    isAllRecordsSelected,
    selectedRecord,
    activeEditTabs,
    activeType,
    activeEditTab,
    setActiveEditTabByType,
    selectedFieldEntriesForTab,
    isPlainObject,
    toFieldLabel,
    handlePrimitiveFieldChange,
    npcFactionOptions,
    handleNpcPositionFieldChange,
    normalizeHexColor,
    npcSpriteSearchQuery,
    setNpcSpriteSearchQuery,
    filteredNpcSpriteOptions,
    buildSpritePreviewDataUrl,
    npcSpriteOptions,
    contentDataByType,
    patchSelectedRecord,
    activeSpritePaintSymbol,
    setActiveSpritePaintSymbol,
    selectedSpriteEditorSize,
    getSpriteCellSymbol,
    getSpritePalette,
    paintSpriteCell,
    colorPaletteEntries,
  } = ctx;
  const isPointerPaintingRef = useRef(false);
  const selectedSpriteInfoPreviewUrl = (activeType === "sprites" || activeType === "tiles") && selectedRecord
    ? buildSpritePreviewDataUrl(selectedRecord, 4)
    : null;
  const [spriteSelectorOpen, setSpriteSelectorOpen] = useState(false);
  const getColorSymbol = (entry: { key?: string; sourceKey?: string; originalName?: string }) => String(entry.key || entry.sourceKey || entry.originalName || "").trim().charAt(0);
  const normalizedColorEntries = colorPaletteEntries
    .map((entry) => ({
      symbol: getColorSymbol(entry),
      color: String(entry.color || "#ffffff"),
    }))
    .filter((entry) => Boolean(entry.symbol));
  const gridColumns = 5;
  const transparentEntry = { symbol: ".", color: "#00000000" };
  const transparentPadCount = (gridColumns - 1 - (normalizedColorEntries.length % gridColumns) + gridColumns) % gridColumns;
  const paletteGridEntries = [
    ...normalizedColorEntries,
    ...Array.from({ length: transparentPadCount }, (_, idx) => ({ symbol: `__pad_${idx}`, color: "", isSpacer: true })),
    transparentEntry,
  ];
  const currentColorEntry = (activeSpritePaintSymbol === ".")
    ? transparentEntry
    : (normalizedColorEntries.find((entry) => entry.symbol === activeSpritePaintSymbol) || normalizedColorEntries[0] || transparentEntry);
  const displayColor = currentColorEntry.symbol === "." ? "transparent" : currentColorEntry.color;
  const displaySymbol = currentColorEntry ? currentColorEntry.symbol : (activeSpritePaintSymbol || "?");
  const painterWidth = activeType === "sprites" ? SPRITE_CANVAS_SIZE : selectedSpriteEditorSize.width;
  const painterHeight = activeType === "sprites" ? SPRITE_CANVAS_SIZE : selectedSpriteEditorSize.height;
  const paintAt = (x: number, y: number) => {
    patchSelectedRecord((record) => paintSpriteCell(record, x, y, activeSpritePaintSymbol));
  };

  return (
    <>
      {!isAllRecordsSelected ? <h2>Selected Record</h2> : null}
      {!isAllRecordsSelected && selectedRecord && activeEditTabs.length > 1 ? (
        <div className="edit-page-tabs">
          {activeEditTabs.map((tab) => (
            <button
              key={`edit-tab-${activeType}-${tab}`}
              type="button"
              className={`edit-tab ${activeEditTab === tab ? "is-active" : ""}`}
              onClick={() => setActiveEditTabByType((prev) => ({ ...prev, [activeType]: tab }))}
            >
              {tab}
            </button>
          ))}
        </div>
      ) : null}
      {!isAllRecordsSelected && !selectedRecord ? <p className="muted">Select or add a record to start editing.</p> : null}
      {!isAllRecordsSelected && selectedRecord ? (
        <div className="fields-grid">
          {selectedFieldEntriesForTab.map(([key, value]) => {
            const keyLower = String(key || "").toLowerCase();
            if ((activeType === "sprites" || activeType === "tiles") && activeEditTab === "Data" && (key === "palette" || key === "rows")) {
              return null;
            }

            if (activeType === "npc_templates" && activeEditTab === "General" && keyLower === "spriteid") {
              return null;
            }

            if (activeType === "npc_templates" && activeEditTab === "General" && keyLower === "defaultdialogueid") {
              const allDialogues = (() => {
                const payload = contentDataByType.dialogues;
                const raw = payload && Array.isArray(payload.dialogues) ? payload.dialogues as unknown[] : [];
                return raw.filter((d): d is Record<string, unknown> => Boolean(d) && typeof d === "object" && !Array.isArray(d));
              })();
              const currentValue = String(selectedRecord.defaultDialogueId || "");
              return (
                <div key={key} className="field-row">
                  <label htmlFor="field-default-dialogue-id">Default Dialogue</label>
                  <select
                    id="field-default-dialogue-id"
                    value={currentValue}
                    onChange={(event) => handlePrimitiveFieldChange("defaultDialogueId", event.target.value)}
                  >
                    <option value="">None</option>
                    {allDialogues.map((dlg, idx) => {
                      const dlgId = String(dlg.id || idx);
                      const dlgName = String(dlg.name || dlgId);
                      return (
                        <option key={`dlg-opt-${dlgId}`} value={dlgId}>
                          {dlgName !== dlgId ? `${dlgName} (${dlgId})` : dlgId}
                        </option>
                      );
                    })}
                  </select>
                </div>
              );
            }

            if ((activeType === "npcs" && (activeEditTab === "General" || activeEditTab === "Overrides") && keyLower === "faction")
              || (activeType === "npc_templates" && activeEditTab === "General" && keyLower === "faction")) {
              const factionField = "faction";
              const currentFaction = String(selectedRecord[factionField] || "");
              return (
                <div key={key} className="field-row">
                  <label htmlFor="field-faction-id">Faction</label>
                  <select
                    id="field-faction-id"
                    value={currentFaction}
                    onChange={(event) => handlePrimitiveFieldChange(factionField, event.target.value)}
                  >
                    <option value="">None</option>
                    {npcFactionOptions.map((faction) => (
                      <option key={`faction-opt-${faction.id}`} value={faction.id}>
                        {faction.name ? `${faction.name} (${faction.id})` : faction.id}
                      </option>
                    ))}
                  </select>
                </div>
              );
            }

            if (activeType === "npcs" && activeEditTab === "General" && keyLower === "position") {
              const position = isPlainObject(selectedRecord.position) ? (selectedRecord.position as JsonObject) : {};
              const posX = Number(position.x ?? 10);
              const posY = Number(position.y ?? 10);
              return (
                <div key={key} className="field-row">
                  <label>{toFieldLabel(key)}</label>
                  <div className="grid-2">
                    <div>
                      <label htmlFor="field-position-x">X</label>
                      <input
                        id="field-position-x"
                        type="number"
                        value={Number.isFinite(posX) ? String(posX) : "10"}
                        onChange={(event) => handleNpcPositionFieldChange("x", event.target.value)}
                      />
                    </div>
                    <div>
                      <label htmlFor="field-position-y">Y</label>
                      <input
                        id="field-position-y"
                        type="number"
                        value={Number.isFinite(posY) ? String(posY) : "10"}
                        onChange={(event) => handleNpcPositionFieldChange("y", event.target.value)}
                      />
                    </div>
                  </div>
                </div>
              );
            }

            if (activeType === "factions" && keyLower === "color") {
              const colorValue = normalizeHexColor(value);
              return (
                <div key={key} className="field-row">
                  <label htmlFor="field-faction-color">Color</label>
                  <div className="faction-color-row">
                    <input
                      id="field-faction-color"
                      type="color"
                      value={colorValue}
                      onChange={(event) => handlePrimitiveFieldChange("color", event.target.value)}
                    />
                    <input
                      value={String(value === null ? "" : value || "")}
                      onChange={(event) => handlePrimitiveFieldChange("color", event.target.value)}
                      placeholder="#7aa2ff"
                    />
                  </div>
                </div>
              );
            }

            if (Array.isArray(value) || (value !== null && typeof value === "object")) {
              return (
                <div key={key} className="field-row">
                  <label>{toFieldLabel(key)}</label>
                  <p className="muted">Complex value. Edit in Raw JSON below.</p>
                </div>
              );
            }

            if (typeof value === "boolean") {
              return (
                <div key={key} className="field-row">
                  <label htmlFor={`field-${key}`}>{toFieldLabel(key)}</label>
                  <select id={`field-${key}`} value={String(value)} onChange={(event) => handlePrimitiveFieldChange(key, event.target.value)}>
                    <option value="true">true</option>
                    <option value="false">false</option>
                  </select>
                </div>
              );
            }

            return (
              <div key={key} className="field-row">
                <label htmlFor={`field-${key}`}>{toFieldLabel(key)}</label>
                <input
                  id={`field-${key}`}
                  type={typeof value === "number" ? "number" : "text"}
                  value={value === null ? "" : String(value)}
                  onChange={(event) => handlePrimitiveFieldChange(key, event.target.value)}
                />
              </div>
            );
          })}

          {(activeType === "npcs" && activeEditTab === "Overrides") || (activeType === "npc_templates" && activeEditTab === "General") ? (
            <div key="sprite-picker" className="field-row">
              <div
                className="sprite-picker-header"
                role="button"
                tabIndex={0}
                onClick={() => setSpriteSelectorOpen((prev) => !prev)}
                onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); setSpriteSelectorOpen((prev) => !prev); } }}
              >
                <span className="sprite-picker-header-label">{toFieldLabel("spriteId")}</span>
                {(() => {
                  const activeSpriteId = String(selectedRecord.spriteId || "").trim();
                  const activeSpriteRecord = npcSpriteOptions.find((s) => String(s.id || "").trim() === activeSpriteId);
                  const previewUrl = activeSpriteRecord ? buildSpritePreviewDataUrl(activeSpriteRecord, 2) : null;
                  return activeSpriteId ? (
                    <span className="sprite-picker-header-preview">
                      {previewUrl ? <img className="sprite-thumb sprite-thumb-list" src={previewUrl} alt="" aria-hidden="true" /> : null}
                      <span className="sprite-picker-header-id">{activeSpriteId}</span>
                    </span>
                  ) : <span className="sprite-picker-header-id muted">None selected</span>;
                })()}
                <span className="sprite-picker-header-chevron">{spriteSelectorOpen ? "▲" : "▼"}</span>
              </div>
              {spriteSelectorOpen ? (
                <>
                  <input
                    className="npc-sprite-search"
                    placeholder="Search sprites by id or name"
                    value={npcSpriteSearchQuery}
                    onChange={(event) => setNpcSpriteSearchQuery(event.target.value)}
                  />
                  <div className="npc-sprite-picker">
                    {filteredNpcSpriteOptions.map((spriteRecord, spriteIndex) => {
                      const spriteId = String(spriteRecord.id || `sprite_${spriteIndex}`).trim();
                      const spriteName = String(spriteRecord.name || spriteId || `Sprite ${spriteIndex + 1}`);
                      const previewUrl = buildSpritePreviewDataUrl(spriteRecord, 2);
                      return (
                        <button
                          key={`npc-sprite-option-${spriteId}-${spriteIndex}`}
                          type="button"
                          className={`npc-sprite-card ${String(selectedRecord.spriteId || "").trim() === spriteId ? "is-active" : ""}`}
                          onClick={() => { handlePrimitiveFieldChange("spriteId", spriteId); setSpriteSelectorOpen(false); }}
                          title={`${spriteId} - ${spriteName}`}
                        >
                          {previewUrl ? (
                            <img className="sprite-thumb sprite-thumb-list" src={previewUrl} alt="" aria-hidden="true" />
                          ) : (
                            <span className="sprite-thumb sprite-thumb-list sprite-thumb-empty" aria-hidden="true" />
                          )}
                          <span className="npc-sprite-card-label">{spriteName}</span>
                        </button>
                      );
                    })}
                  </div>
                  {npcSpriteOptions.length === 0 ? <p className="muted">No sprites available yet. Add sprites under the Sprites content tab.</p> : null}
                  {npcSpriteOptions.length > 0 && filteredNpcSpriteOptions.length === 0 ? <p className="muted">No sprite matches that search.</p> : null}
                </>
              ) : null}
            </div>
          ) : null}

          {(activeType === "sprites" || activeType === "tiles") && activeEditTab === "Information" ? (
            <div className="field-row sprite-preview-field">
              <label>Preview</label>
              {selectedSpriteInfoPreviewUrl ? (
                <img className="sprite-thumb sprite-thumb-info" src={selectedSpriteInfoPreviewUrl} alt="Sprite preview" />
              ) : (
                <p className="muted">No sprite preview available yet. Add rows in the Data tab.</p>
              )}
            </div>
          ) : null}

          {(activeType === "sprites" || activeType === "tiles") && activeEditTab === "Data" ? (
            <div className="sprite-data-editor">
              <div className="sprite-data-card">
                <div className="sprite-data-head">
                  <h4>Paint Brush</h4>
                </div>
                <p className="muted">Select a color from the palette below to paint with.</p>
                <div className="sprite-color-current">
                  <div className="sprite-color-current-label">Current Color</div>
                  <div className={`sprite-color-current-swatch ${displaySymbol === "." ? "is-transparent" : ""}`} style={{ backgroundColor: displayColor }} />
                  <div className="sprite-color-current-value">{displaySymbol}</div>
                </div>
                <div className="color-palette-grid5">
                  {paletteGridEntries.map((colorEntry, colorIndex) => {
                    if ("isSpacer" in colorEntry) {
                      return <span key={`sprite-palette-spacer-${colorIndex}`} className="color-pixel-spacer" aria-hidden="true" />;
                    }
                    const isTransparent = colorEntry.symbol === ".";
                    return (
                      <button
                        key={`sprite-palette-color-${colorIndex}`}
                        type="button"
                        className={`color-pixel-btn ${activeSpritePaintSymbol === colorEntry.symbol ? "is-active" : ""} ${isTransparent ? "is-transparent" : ""}`}
                        style={{ backgroundColor: isTransparent ? "transparent" : colorEntry.color }}
                        onClick={() => setActiveSpritePaintSymbol(colorEntry.symbol)}
                        title={isTransparent ? "Paint with . (transparent / no color)" : `Paint with ${colorEntry.symbol} - ${colorEntry.color}`}
                      >
                        <span className="color-pixel-label">{colorEntry.symbol}</span>
                      </button>
                    );
                  })}
                </div>
                <div
                  className="sprite-painter-grid"
                  style={{ gridTemplateColumns: `repeat(${painterWidth}, 30px)` }}
                  onPointerUp={() => {
                    isPointerPaintingRef.current = false;
                  }}
                  onPointerLeave={() => {
                    isPointerPaintingRef.current = false;
                  }}
                >
                  {Array.from({ length: painterHeight }).map((_, y) => (
                    Array.from({ length: painterWidth }).map((_, x) => {
                      const symbol = getSpriteCellSymbol(selectedRecord, x, y);
                      const color = getSpritePalette(selectedRecord)[symbol] || "#00000000";
                      const patternColors = ["#c0c0c0", "#9a9a9a"];
                      const cellPattern = patternColors[(x + y) % patternColors.length];
                      return (
                        <button
                          key={`sprite-cell-${x}-${y}`}
                          type="button"
                          className={`sprite-cell ${symbol === "." ? "is-transparent" : ""}`}
                          style={{
                            ["--cell-bg" as string]: cellPattern,
                            ["--paint-color" as string]: symbol === "." ? "transparent" : color,
                          }}
                          onPointerDown={(event) => {
                            event.preventDefault();
                            isPointerPaintingRef.current = true;
                            paintAt(x, y);
                          }}
                          onPointerEnter={() => {
                            if (!isPointerPaintingRef.current) {
                              return;
                            }
                            paintAt(x, y);
                          }}
                          title={`(${x + 1},${y + 1}) '${symbol}'`}
                        />
                      );
                    })
                  ))}
                </div>
              </div>
            </div>
          ) : null}

          {selectedFieldEntriesForTab.length === 0 ? <p className="muted">No direct fields in this tab. Use Raw JSON if needed.</p> : null}
        </div>
      ) : null}
    </>
  );
}
