import { useMemo, useState } from "react";
import { createPortal } from "react-dom";
import type { ApiSettings } from "../../../types";
import Button from "../../../components/Button";
import DataGrid, { type DataGridColumn } from "../../../components/table/DataGrid";
import ToggleSwitch from "../../../components/ToggleSwitch";
import { getBool, getText } from "../utils/draftEditor";
import { createAttachmentRule, nextAttachmentLabel, summarizeAttachmentRules, type AttachmentBasePath, type AttachmentRule } from "../utils/attachments";
import ManagedFileChooser, { type ManagedAttachmentSelection } from "./ManagedFileChooser";

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

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

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

type FileChooserState = {
  ruleIndex: number;
  basePath: AttachmentBasePath | null;
};

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

  function closeOverlay() {
    setOpen(false);
  }

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

  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">{title}</h2>
          <button className="modal-close" onClick={closeOverlay}>×</button>
        </header>
        <div className="modal-body attachment-rules-body">
          <AttachmentRulesDataGrid
            rules={rules}
            settings={settings}
            campaignId={campaignId}
            disabled={disabled}
            emptyText={emptyText}
            basePaths={basePaths}
            activeChooserRuleIndex={null}
            onChange={onChange}
          />
        </div>
        <footer className="modal-footer">
          <Button variant="primary" onClick={addOverlayRule} disabled={disabled}>Add file</Button>
          <Button 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({
  showAddButton = true,
  onChange,
  ...tableProps
}: AttachmentRulesTableProps) {
  function addRule() {
    onChange([
      ...tableProps.rules,
      createAttachmentRule(tableProps.basePaths?.[0]?.path ?? "", nextAttachmentLabel(tableProps.rules), tableProps.basePaths?.[0]?.id ?? "")
    ]);
  }

  return (
    <div className="attachment-rules-editor">
      <div className="attachment-rules-main">
        <AttachmentRulesDataGrid {...tableProps} onChange={onChange} />
        {showAddButton && (
          <div className="button-row compact-actions attachment-rules-footer-actions">
            <Button variant="primary" onClick={addRule} disabled={tableProps.disabled}>Add file</Button>
          </div>
        )}
      </div>
    </div>
  );
}

export function AttachmentRulesDataGrid({
  rules,
  settings,
  campaignId,
  disabled = false,
  emptyText = "No attachment files or matching rules configured yet.",
  basePaths = [],
  id = "attachment-rules",
  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 removeRule(index: number) {
    setFileChooser(null);
    onChange(rules.filter((_, currentIndex) => currentIndex !== index));
  }

  function openFileChooser(ruleIndex: number) {
    if (onOpenFileChooser) {
      onOpenFileChooser(ruleIndex);
      return;
    }
    const rule = rules[ruleIndex] ?? {};
    const currentPath = getText(rule, "base_dir", basePaths[0]?.path ?? "");
    const currentBasePathId = getText(rule, "base_path_id");
    const basePath = basePaths.find((item) => item.id === currentBasePathId) ?? basePaths.find((item) => item.path === currentPath) ?? basePaths[0] ?? null;
    setFileChooser({ ruleIndex, basePath });
  }

  function selectAttachment(selection: ManagedAttachmentSelection) {
    if (!fileChooser) return;
    const currentRule = rules[fileChooser.ruleIndex] ?? {};
    patchRule(fileChooser.ruleIndex, {
      base_path_id: fileChooser.basePath?.id ?? "",
      base_dir: fileChooser.basePath?.path ?? (selection.folderPath || "."),
      file_filter: selection.fileFilter,
      type: selection.selectionType === "file" ? "direct" : "pattern",
      include_subdirs: false,
      label: getText(currentRule, "label") || `Attachment ${fileChooser.ruleIndex + 1}`
    });
    setFileChooser(null);
  }

  return (
    <>
      <DataGrid
        id={id}
        rows={rules}
        columns={attachmentRuleColumns({ disabled, basePaths, activeChooserRuleIndex: activeChooserRuleIndex ?? fileChooser?.ruleIndex ?? null, patchRule, openFileChooser, removeRule })}
        getRowKey={(rule, index) => String(rule.id ?? index)}
        emptyText={emptyText}
        className="attachment-rules-table-wrap attachment-rules-table"
        rowClassName={(_rule, index) => (activeChooserRuleIndex ?? fileChooser?.ruleIndex) === index ? "is-choosing-file" : undefined}
      />
      {fileChooser && (
        <ManagedFileChooser
          open
          settings={settings}
          campaignId={campaignId}
          mode="attachment"
          source={fileChooser.basePath?.source}
          basePath={fileChooser.basePath?.path ?? "."}
          initialPattern={getText(rules[fileChooser.ruleIndex], "file_filter")}
          rememberKey={`${id}:${String(rules[fileChooser.ruleIndex]?.id ?? fileChooser.ruleIndex)}`}
          onClose={() => setFileChooser(null)}
          onSelectAttachment={selectAttachment}
        />
      )}
    </>
  );
}

type AttachmentRuleColumnContext = {
  disabled: boolean;
  basePaths: AttachmentBasePath[];
  activeChooserRuleIndex: number | null;
  patchRule: (index: number, patch: Partial<AttachmentRule>) => void;
  openFileChooser: (ruleIndex: number) => void;
  removeRule: (index: number) => void;
};

function attachmentRuleColumns({ disabled, basePaths, activeChooserRuleIndex: _activeChooserRuleIndex, patchRule, openFileChooser, removeRule }: AttachmentRuleColumnContext): DataGridColumn<AttachmentRule>[] {
  return [
    { id: "label", header: "Label", width: 190, resizable: true, sortable: true, filterable: true, sticky: "start", render: (rule, index) => <input value={getText(rule, "label")} disabled={disabled} placeholder="Attachment label" onChange={(event) => patchRule(index, { label: event.target.value })} />, value: (rule) => getText(rule, "label") },
    {
      id: "base_path",
      header: "Base path",
      width: 250,
      sortable: true,
      filterable: true,
      render: (rule, index) => {
        const currentBasePathValue = getText(rule, "base_dir", basePaths[0]?.path ?? "");
        const currentBasePathId = getText(rule, "base_path_id");
        const selectedBasePath = basePaths.find((basePath) => basePath.id === currentBasePathId) ?? basePaths.find((basePath) => basePath.path === currentBasePathValue) ?? basePaths[0];
        return basePaths.length > 0 ? (
          <select
            value={selectedBasePath?.id ?? ""}
            disabled={disabled}
            onChange={(event) => {
              const nextBasePath = basePaths.find((basePath) => basePath.id === event.target.value);
              if (nextBasePath) patchRule(index, { base_path_id: nextBasePath.id, base_dir: nextBasePath.path });
            }}
          >
            {basePaths.map((basePath) => <option key={basePath.id} value={basePath.id}>{basePath.name || basePath.path}</option>)}
          </select>
        ) : (
          <input value={currentBasePathValue} disabled={disabled} readOnly placeholder="optional/folder" />
        );
      },
      value: (rule) => getText(rule, "base_dir", basePaths[0]?.path ?? "")
    },
    {
      id: "file_filter",
      header: "File / pattern",
      width: "minmax(260px, 1fr)",
      resizable: true,
      sortable: true,
      filterable: true,
      render: (rule, index) => (
        <div className="field-with-action split-field-action">
          <input
            className="chooser-display-input"
            value={getText(rule, "file_filter")}
            disabled={disabled}
            readOnly
            tabIndex={-1}
            placeholder="Choose a managed file or pattern"
            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>
      ),
      value: (rule) => getText(rule, "file_filter")
    },
    { id: "required", header: "Required", width: 175, sortable: true, filterable: true, render: (rule, index) => <ToggleSwitch label="Required" checked={getBool(rule, "required", true)} disabled={disabled} onChange={(checked) => patchRule(index, { required: checked })} />, value: (rule) => getBool(rule, "required", true) ? "required" : "optional" },
    {
      id: "actions",
      header: "",
      width: 145,
      sticky: "end",
      render: (_rule, index) => <Button variant="danger" onClick={() => removeRule(index)} disabled={disabled}>Remove</Button>
    }
  ];
}
