import { useMemo, useState } from "react";
import { createPortal } from "react-dom";
import Button from "../../../components/Button";
import ToggleSwitch from "../../../components/ToggleSwitch";
import { getBool, getText } from "../utils/draftEditor";
import { createAttachmentRule, mockAttachmentFiles, summarizeAttachmentRules, type AttachmentBasePath, type AttachmentRule } from "../utils/attachments";

export type { AttachmentBasePath, AttachmentRule } from "../utils/attachments";

type AttachmentRulesOverlayProps = {
  title: string;
  rules: AttachmentRule[];
  disabled?: boolean;
  buttonLabel?: string;
  emptyText?: string;
  basePaths?: AttachmentBasePath[];
  onChange: (rules: AttachmentRule[]) => void;
};

type AttachmentRulesTableProps = {
  rules: AttachmentRule[];
  disabled?: boolean;
  emptyText?: string;
  basePaths?: AttachmentBasePath[];
  showAddButton?: boolean;
  activeChooserRuleIndex?: number | null;
  onOpenFileChooser?: (ruleIndex: number) => void;
  onChange: (rules: AttachmentRule[]) => void;
};

type FileChooserState = {
  ruleIndex: number;
  basePath: string;
};

export default function AttachmentRulesOverlay({
  title,
  rules,
  disabled = false,
  buttonLabel,
  emptyText = "No attachment files or matching rules configured yet.",
  basePaths = [],
  onChange
}: AttachmentRulesOverlayProps) {
  const [open, setOpen] = useState(false);
  const [fileChooser, setFileChooser] = useState<FileChooserState | null>(null);
  const summary = useMemo(() => summarizeAttachmentRules(rules), [rules]);
  const label = buttonLabel ?? `direct: ${summary.direct} / rules: ${summary.rules}`;

  function patchRule(index: number, patch: Partial<AttachmentRule>) {
    onChange(rules.map((rule, currentIndex) => currentIndex === index ? { ...rule, ...patch } : rule));
  }

  function openFileChooser(ruleIndex: number) {
    const rule = rules[ruleIndex] ?? {};
    setFileChooser({ ruleIndex, basePath: getText(rule, "base_dir", basePaths[0]?.path ?? "") });
  }

  function selectFileFilter(fileFilter: string) {
    if (!fileChooser) return;
    patchRule(fileChooser.ruleIndex, { file_filter: fileFilter });
    setFileChooser(null);
  }

  function closeOverlay() {
    setFileChooser(null);
    setOpen(false);
  }

  const activeRule = fileChooser ? rules[fileChooser.ruleIndex] : undefined;
  const activeBasePath = fileChooser
    ? getText(activeRule ?? {}, "base_dir", fileChooser.basePath || basePaths[0]?.path || "")
    : "";

  const dialog = open ? createPortal(
    <div className="overlay-backdrop" role="dialog" aria-modal="true" aria-labelledby="attachment-rules-title">
      <div className="modal-panel attachment-rules-modal">
        <header className="modal-header">
          <h2 id="attachment-rules-title">{fileChooser ? "Choose file or pattern" : title}</h2>
          <button className="modal-close" onClick={closeOverlay}>×</button>
        </header>
        <div className="modal-body attachment-rules-body">
          {fileChooser ? (
            <MockFileChooserContent
              basePath={activeBasePath}
              onSelect={selectFileFilter}
              onClose={() => setFileChooser(null)}
            />
          ) : (
            <>
              <p className="muted small-note">Use direct files for fixed attachments and rules/patterns for files resolved during build.</p>
              <AttachmentRulesTable
                rules={rules}
                disabled={disabled}
                emptyText={emptyText}
                basePaths={basePaths}
                activeChooserRuleIndex={null}
                onOpenFileChooser={openFileChooser}
                onChange={onChange}
              />
            </>
          )}
        </div>
        <footer className="modal-footer">
          {fileChooser ? (
            <Button onClick={() => setFileChooser(null)}>Back to rules</Button>
          ) : (
            <Button variant="primary" onClick={closeOverlay}>Close</Button>
          )}
        </footer>
      </div>
    </div>,
    document.body
  ) : null;

  return (
    <>
      <Button className="attachment-summary-button" onClick={() => setOpen(true)} disabled={disabled && rules.length === 0} title={`${summary.direct} direct file(s), ${summary.rules} rule(s) / pattern(s)`}>
        {label}
      </Button>
      {dialog}
    </>
  );
}

export function AttachmentRulesTable({
  rules,
  disabled = false,
  emptyText = "No attachment files or matching rules configured yet.",
  basePaths = [],
  showAddButton = true,
  activeChooserRuleIndex = null,
  onOpenFileChooser,
  onChange
}: AttachmentRulesTableProps) {
  const [fileChooser, setFileChooser] = useState<FileChooserState | null>(null);

  function patchRule(index: number, patch: Partial<AttachmentRule>) {
    onChange(rules.map((rule, currentIndex) => currentIndex === index ? { ...rule, ...patch } : rule));
  }

  function addRule() {
    onChange([...rules, createAttachmentRule(basePaths[0]?.path ?? "")]);
  }

  function removeRule(index: number) {
    setFileChooser(null);
    onChange(rules.filter((_, currentIndex) => currentIndex !== index));
  }

  function openFileChooser(ruleIndex: number) {
    if (onOpenFileChooser) {
      onOpenFileChooser(ruleIndex);
      return;
    }
    const rule = rules[ruleIndex] ?? {};
    setFileChooser({ ruleIndex, basePath: getText(rule, "base_dir", basePaths[0]?.path ?? "") });
  }

  function selectFileFilter(fileFilter: string) {
    if (!fileChooser) return;
    patchRule(fileChooser.ruleIndex, { file_filter: fileFilter });
    setFileChooser(null);
  }

  const activeRule = fileChooser ? rules[fileChooser.ruleIndex] : undefined;
  const activeBasePath = fileChooser
    ? getText(activeRule ?? {}, "base_dir", fileChooser.basePath || basePaths[0]?.path || "")
    : "";

  return (
    <div className="attachment-rules-editor">
      <div className="attachment-rules-main">
        {rules.length === 0 ? (
          <p className="muted attachment-rules-empty">{emptyText}</p>
        ) : (
          <div className="app-table-wrap attachment-rules-table-wrap">
            <table className="app-table attachment-rules-table">
              <thead>
                <tr>
                  <th>Label</th>
                  <th>Base path</th>
                  <th>File / pattern</th>
                  <th>Required</th>
                  <th>Subdirs</th>
                  <th></th>
                </tr>
              </thead>
              <tbody>
                {rules.map((rule, index) => {
                  const currentBasePath = getText(rule, "base_dir", basePaths[0]?.path ?? "");
                  const isChoosingFile = (activeChooserRuleIndex ?? fileChooser?.ruleIndex) === index;
                  return (
                    <tr key={String(rule.id ?? index)} className={isChoosingFile ? "is-choosing-file" : undefined}>
                      <td><input value={getText(rule, "label")} disabled={disabled} placeholder="Attachment label" onChange={(event) => patchRule(index, { label: event.target.value })} /></td>
                      <td>
                        {basePaths.length > 0 ? (
                          <select value={currentBasePath} disabled={disabled} onChange={(event) => patchRule(index, { base_dir: event.target.value })}>
                            {basePaths.map((basePath) => <option key={basePath.id} value={basePath.path}>{basePath.name || basePath.path}</option>)}
                          </select>
                        ) : (
                          <input value={currentBasePath} disabled={disabled} readOnly placeholder="optional/folder" />
                        )}
                      </td>
                      <td>
                        <div className="field-with-action">
                          <input
                            className="chooser-display-input"
                            value={getText(rule, "file_filter")}
                            disabled={disabled}
                            readOnly
                            tabIndex={-1}
                            placeholder="file.pdf or {{local:id}}.pdf"
                            onClick={() => !disabled && openFileChooser(index)}
                            onKeyDown={(event) => {
                              if (!disabled && (event.key === "Enter" || event.key === " ")) {
                                event.preventDefault();
                                openFileChooser(index);
                              }
                            }}
                          />
                          <Button onClick={() => openFileChooser(index)} disabled={disabled}>Choose</Button>
                        </div>
                      </td>
                      <td><ToggleSwitch label="Required" checked={getBool(rule, "required", true)} disabled={disabled} onChange={(checked) => patchRule(index, { required: checked })} /></td>
                      <td><ToggleSwitch label="Subdirs" checked={getBool(rule, "include_subdirs")} disabled={disabled} onChange={(checked) => patchRule(index, { include_subdirs: checked })} /></td>
                      <td className="table-action-cell"><Button variant="danger" onClick={() => removeRule(index)} disabled={disabled}>Remove</Button></td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </div>
        )}
        {showAddButton && (
          <div className="button-row compact-actions attachment-rules-footer-actions">
            <Button onClick={addRule} disabled={disabled}>Add file</Button>
          </div>
        )}
      </div>
      {fileChooser && (
        <MockFileChooserOverlay
          basePath={activeBasePath}
          onSelect={selectFileFilter}
          onClose={() => setFileChooser(null)}
        />
      )}
    </div>
  );
}

function MockFileChooserOverlay({ basePath, onSelect, onClose }: { basePath: string; onSelect: (fileFilter: string) => void; onClose: () => void }) {
  return createPortal(
    <div className="overlay-backdrop" role="dialog" aria-modal="true" aria-labelledby="mock-file-chooser-title">
      <div className="modal-panel attachment-rules-modal">
        <header className="modal-header">
          <h2 id="mock-file-chooser-title">Choose file or pattern</h2>
          <button className="modal-close" onClick={onClose}>×</button>
        </header>
        <div className="modal-body attachment-rules-body">
          <MockFileChooserContent basePath={basePath} onSelect={onSelect} onClose={onClose} />
        </div>
        <footer className="modal-footer">
          <Button onClick={onClose}>Cancel</Button>
        </footer>
      </div>
    </div>,
    document.body
  );
}

function MockFileChooserContent({ basePath, onSelect, onClose }: { basePath: string; onSelect: (fileFilter: string) => void; onClose: () => void }) {
  return (
    <div className="attachment-file-browser-content" aria-label="Choose file or pattern">
      <p className="muted small-note">Mock browser below <code>{basePath || "."}</code>. Later this will browse uploaded files and directories.</p>
      <div className="placeholder-stack attachment-file-browser-list">
        {mockAttachmentFiles.map((file) => (
          <Button key={file} onClick={() => onSelect(file)}>
            <code>{file}</code>
          </Button>
        ))}
      </div>
      <div className="button-row compact-actions attachment-file-browser-actions">
        <Button onClick={onClose}>Back</Button>
      </div>
    </div>
  );
}
