import { FormEvent, useEffect, useMemo, useState } from "react";
import { ArrowDown, ArrowUp, Play, Save } from "lucide-react";
import type {
  AutomationFrequency,
  AutomationScheduleDto,
  AutomationSettingsDto,
  MetadataSourcesConfigDto
} from "@readabook/shared";
import { api, getApiFallback } from "../api/client";
import { ErrorRibbon, LoadingState, Panel } from "../components/ui";
import {
  type AdminMetadataProviderId,
  type AdminMetadataSourcesConfig,
  defaultMetadataSources,
  metadataSourcesPayload,
  moveSource,
  normalizeMetadataSources,
  providerLabels,
  providerUiMessage,
  providerUiState,
  providerUiStateLabel,
  scheduleDays,
  scheduleSummary
} from "./adminAutomation";

type AdminAutomationTab = "sources" | "automation";
type ApiState<T> = {
  initial: T | null;
  draft: T | null;
  loading: boolean;
  saving: boolean;
  error?: string;
  success?: string;
};

const defaultMetadataConfig: AdminMetadataSourcesConfig = {
  isbnPriorityEnabled: true,
  sources: defaultMetadataSources
};

const defaultAutomationSettings: AutomationSettingsDto = {
  watchLibraries: false,
  autoEnrichNewBooks: false,
  scanSchedule: { frequency: "disabled", time: "03:00", dayOfWeek: 1 },
  enrichSchedule: { frequency: "disabled", time: "04:00", dayOfWeek: 1 }
};

export function AdminAutomationPage() {
  const [tab, setTab] = useState<AdminAutomationTab>("sources");
  const [metadataState, setMetadataState] = useState<ApiState<AdminMetadataSourcesConfig>>({
    initial: null,
    draft: null,
    loading: true,
    saving: false
  });
  const [automationState, setAutomationState] = useState<ApiState<AutomationSettingsDto>>({
    initial: null,
    draft: null,
    loading: true,
    saving: false
  });
  const [apiKeys, setApiKeys] = useState<Partial<Record<AdminMetadataProviderId, string>>>({});

  const metadataDirty = useMemo(
    () => Boolean(metadataState.initial && metadataState.draft && JSON.stringify(metadataState.initial) !== JSON.stringify(metadataState.draft)),
    [metadataState.initial, metadataState.draft]
  );
  const automationDirty = useMemo(
    () =>
      Boolean(automationState.initial && automationState.draft && JSON.stringify(automationState.initial) !== JSON.stringify(automationState.draft)),
    [automationState.initial, automationState.draft]
  );

  async function refreshMetadata() {
    setMetadataState((current) => ({ ...current, loading: true, error: undefined, success: undefined }));
    try {
      const next = normalizeMetadataSources(await api.metadataSources());
      setMetadataState({ initial: next, draft: next, loading: false, saving: false });
      setApiKeys({});
    } catch (error) {
      const fallback = getApiFallback<MetadataSourcesConfigDto | AdminMetadataSourcesConfig>(error);
      const next = normalizeMetadataSources(fallback ?? defaultMetadataConfig);
      setMetadataState({
        initial: next,
        draft: next,
        loading: false,
        saving: false,
        error: fallback ? "Sources chargees en mode degrade." : "Lecture des sources impossible."
      });
    }
  }

  async function refreshAutomation() {
    setAutomationState((current) => ({ ...current, loading: true, error: undefined, success: undefined }));
    try {
      const next = await api.automationSettings();
      setAutomationState({ initial: next, draft: next, loading: false, saving: false });
    } catch (error) {
      const fallback = getApiFallback<AutomationSettingsDto>(error);
      const next = fallback ?? defaultAutomationSettings;
      setAutomationState({
        initial: next,
        draft: next,
        loading: false,
        saving: false,
        error: fallback ? "Automatisation chargee en mode degrade." : "Lecture de l'automatisation impossible."
      });
    }
  }

  useEffect(() => {
    void refreshMetadata();
    void refreshAutomation();
  }, []);

  async function saveMetadata(event: FormEvent) {
    event.preventDefault();
    if (!metadataState.draft) return;
    setMetadataState((current) => ({ ...current, saving: true, error: undefined, success: undefined }));
    try {
      const payload = metadataSourcesPayload(metadataState.draft);
      payload.sources = payload.sources?.map((source) => {
        const apiKey = apiKeys[source.provider]?.trim();
        return apiKey ? { ...source, apiKey } : source;
      });
      const next = normalizeMetadataSources(await api.updateMetadataSources(payload));
      setMetadataState({ initial: next, draft: next, loading: false, saving: false, success: "Sources enregistrees." });
      setApiKeys({});
    } catch (error) {
      setMetadataState((current) => ({
        ...current,
        saving: false,
        error: error instanceof Error ? error.message : "Enregistrement des sources impossible."
      }));
    }
  }

  async function saveAutomation(event: FormEvent) {
    event.preventDefault();
    if (!automationState.draft) return;
    setAutomationState((current) => ({ ...current, saving: true, error: undefined, success: undefined }));
    try {
      const next = await api.updateAutomationSettings(automationState.draft);
      setAutomationState({ initial: next, draft: next, loading: false, saving: false, success: "Automatisation enregistree." });
    } catch (error) {
      setAutomationState((current) => ({
        ...current,
        saving: false,
        error: error instanceof Error ? error.message : "Enregistrement de l'automatisation impossible."
      }));
    }
  }

  async function runNow(kind: "scan" | "enrich") {
    setAutomationState((current) => ({ ...current, error: undefined, success: undefined }));
    try {
      if (kind === "scan") await api.runAutomationScan();
      else await api.runAutomationEnrich();
      setAutomationState((current) => ({
        ...current,
        success: kind === "scan" ? "Scan planifie demande." : "Enrichissement planifie demande."
      }));
    } catch (error) {
      setAutomationState((current) => ({
        ...current,
        error: error instanceof Error ? error.message : "Demande impossible."
      }));
    }
  }

  return (
    <div className="page-grid">
      <Panel className="span-3">
        <div className="section-heading">
          <div>
            <h1>Automatisation & enrichissement</h1>
            <p className="muted-copy">Sources, priorites et taches recurrentes.</p>
          </div>
          <span>{metadataDirty || automationDirty ? "modifications non enregistrees" : "a jour"}</span>
        </div>
        <div className="admin-tabs" role="tablist" aria-label="Automatisation admin">
          <button className={tab === "sources" ? "active" : ""} onClick={() => setTab("sources")} role="tab" aria-selected={tab === "sources"}>
            Sources de métadonnées
          </button>
          <button
            className={tab === "automation" ? "active" : ""}
            onClick={() => setTab("automation")}
            role="tab"
            aria-selected={tab === "automation"}
          >
            Automatisation
          </button>
        </div>
      </Panel>

      {tab === "sources" ? (
        <MetadataSourcesPanel
          state={metadataState}
          dirty={metadataDirty}
          apiKeys={apiKeys}
          setApiKeys={setApiKeys}
          onChange={(draft) => setMetadataState((current) => ({ ...current, draft, success: undefined }))}
          onSubmit={saveMetadata}
          onRefresh={refreshMetadata}
        />
      ) : (
        <AutomationPanel
          state={automationState}
          dirty={automationDirty}
          onChange={(draft) => setAutomationState((current) => ({ ...current, draft, success: undefined }))}
          onSubmit={saveAutomation}
          onRefresh={refreshAutomation}
          onRunNow={runNow}
        />
      )}
    </div>
  );
}

function MetadataSourcesPanel({
  state,
  dirty,
  apiKeys,
  setApiKeys,
  onChange,
  onSubmit,
  onRefresh
}: {
  state: ApiState<AdminMetadataSourcesConfig>;
  dirty: boolean;
  apiKeys: Partial<Record<AdminMetadataProviderId, string>>;
  setApiKeys: (next: Partial<Record<AdminMetadataProviderId, string>>) => void;
  onChange: (draft: AdminMetadataSourcesConfig) => void;
  onSubmit: (event: FormEvent) => void;
  onRefresh: () => Promise<void>;
}) {
  const draft = state.draft;
  if (state.loading && !draft) return <LoadingPanel label="Lecture des sources" />;
  if (!draft) return null;

  const local = draft.sources.find((source) => source.provider === "local");
  const external = draft.sources.filter((source) => source.provider !== "local");

  return (
    <form className="span-3 automation-grid" onSubmit={onSubmit}>
      <Panel className="span-3">
        <div className="section-heading compact-heading">
          <div>
            <h2>Sources de métadonnées</h2>
            <p className="muted-copy">La source locale reste active en premier passage.</p>
          </div>
          <StatusText dirty={dirty} loading={state.loading} />
        </div>
        <ErrorRibbon message={state.error} />
        {state.success && <div className="success-ribbon">{state.success}</div>}
        <label className="toggle-row">
          <input
            type="checkbox"
            checked={draft.isbnPriorityEnabled}
            onChange={(event) => onChange({ ...draft, isbnPriorityEnabled: event.target.checked })}
          />
          <span>
            <strong>Priorite ISBN globale</strong>
            <small>Les correspondances ISBN passent avant les rapprochements titre/auteur.</small>
          </span>
        </label>
      </Panel>

      <Panel className="span-3">
        <div className="provider-list">
          {local && (
            <div className="provider-row provider-local">
              <div>
                <strong>{providerLabels.local}</strong>
                <span>Source locale</span>
              </div>
              <span className="status-pill active">toujours active</span>
            </div>
          )}
          {external.map((source, index) => (
            <div className="provider-row" key={source.provider}>
              <label className="toggle-row">
                <input
                  type="checkbox"
                  checked={source.enabled}
                  onChange={(event) =>
                    onChange({
                      ...draft,
                      sources: draft.sources.map((item) =>
                        item.provider === source.provider ? { ...item, enabled: event.target.checked } : item
                      )
                    })
                  }
                />
                <span>
                  <strong>{providerLabels[source.provider]}</strong>
                  <small>{source.enabled ? "active" : "inactive"}</small>
                </span>
              </label>
              <div className="provider-config">
                <div className="provider-state-line">
                  <span className={`status-pill provider-state-${providerUiState(source)}`}>{providerUiStateLabel(source)}</span>
                  <small>{providerUiMessage(source)}</small>
                </div>
                {source.provider === "comicvine" && (
                  <p className="provider-warning">
                    Usage non commercial uniquement. Verifier la compatibilite avec l'usage de ReadaBook.
                  </p>
                )}
                <label>
                  Cle API
                  <input
                    value={apiKeys[source.provider] ?? ""}
                    onChange={(event) => setApiKeys({ ...apiKeys, [source.provider]: event.target.value })}
                    placeholder={source.hasApiKey ? "cle conservee" : source.requiresCredentials ? "requise" : "optionnelle"}
                  />
                </label>
              </div>
              <div className="provider-actions">
                <button
                  className="ghost-button icon-button"
                  type="button"
                  title="Monter"
                  disabled={index === 0}
                  onClick={() => onChange({ ...draft, sources: moveSource(draft.sources, source.provider, -1) })}
                >
                  <ArrowUp size={16} />
                </button>
                <button
                  className="ghost-button icon-button"
                  type="button"
                  title="Descendre"
                  disabled={index === external.length - 1}
                  onClick={() => onChange({ ...draft, sources: moveSource(draft.sources, source.provider, 1) })}
                >
                  <ArrowDown size={16} />
                </button>
              </div>
            </div>
          ))}
        </div>
      </Panel>

      <SaveBar dirty={dirty} saving={state.saving} onRefresh={onRefresh} />
    </form>
  );
}

function AutomationPanel({
  state,
  dirty,
  onChange,
  onSubmit,
  onRefresh,
  onRunNow
}: {
  state: ApiState<AutomationSettingsDto>;
  dirty: boolean;
  onChange: (draft: AutomationSettingsDto) => void;
  onSubmit: (event: FormEvent) => void;
  onRefresh: () => Promise<void>;
  onRunNow: (kind: "scan" | "enrich") => Promise<void>;
}) {
  const draft = state.draft;
  if (state.loading && !draft) return <LoadingPanel label="Lecture de l'automatisation" />;
  if (!draft) return null;

  return (
    <form className="span-3 automation-grid" onSubmit={onSubmit}>
      <Panel className="span-3">
        <div className="section-heading compact-heading">
          <div>
            <h2>Automatisation</h2>
            <p className="muted-copy">Surveillance des dossiers et traitements planifies.</p>
          </div>
          <StatusText dirty={dirty} loading={state.loading} />
        </div>
        <ErrorRibbon message={state.error} />
        {state.success && <div className="success-ribbon">{state.success}</div>}
        <div className="toggle-stack">
          <label className="toggle-row">
            <input
              type="checkbox"
              checked={draft.watchLibraries}
              onChange={(event) => onChange({ ...draft, watchLibraries: event.target.checked })}
            />
            <span>
              <strong>Watch auto</strong>
              <small>Les bibliotheques actives declenchent un scan quand un fichier change.</small>
            </span>
          </label>
          <label className="toggle-row">
            <input
              type="checkbox"
              checked={draft.autoEnrichNewBooks}
              onChange={(event) => onChange({ ...draft, autoEnrichNewBooks: event.target.checked })}
            />
            <span>
              <strong>Auto enrich new files</strong>
              <small>Les nouveaux livres passent par la chaine d'enrichissement active.</small>
            </span>
          </label>
        </div>
      </Panel>

      <SchedulePanel
        title="Scan planifié"
        schedule={draft.scanSchedule}
        summary={scheduleSummary(draft.scanSchedule, "Scan")}
        runLabel="Lancer un scan"
        onRun={() => onRunNow("scan")}
        onChange={(scanSchedule) => onChange({ ...draft, scanSchedule })}
      />
      <SchedulePanel
        title="Enrichissement planifié"
        schedule={draft.enrichSchedule}
        summary={scheduleSummary(draft.enrichSchedule, "Enrichissement")}
        runLabel="Lancer l'enrichissement"
        onRun={() => onRunNow("enrich")}
        onChange={(enrichSchedule) => onChange({ ...draft, enrichSchedule })}
      />

      <SaveBar dirty={dirty} saving={state.saving} onRefresh={onRefresh} />
    </form>
  );
}

function SchedulePanel({
  title,
  schedule,
  summary,
  runLabel,
  onRun,
  onChange
}: {
  title: string;
  schedule: AutomationScheduleDto;
  summary: string;
  runLabel: string;
  onRun: () => Promise<void>;
  onChange: (schedule: AutomationScheduleDto) => void;
}) {
  function patch(next: Partial<AutomationScheduleDto>) {
    onChange({ ...schedule, ...next });
  }

  return (
    <Panel>
      <div className="section-heading compact-heading">
        <div>
          <h2>{title}</h2>
          <p className="muted-copy">{summary}</p>
        </div>
        <button className="ghost-button icon-text-button" type="button" onClick={() => void onRun()}>
          <Play size={16} />
          {runLabel}
        </button>
      </div>
      <div className="schedule-controls">
        <label>
          Frequence
          <select value={schedule.frequency} onChange={(event) => patch({ frequency: event.target.value as AutomationFrequency })}>
            <option value="disabled">Desactive</option>
            <option value="daily">Daily</option>
            <option value="weekly">Weekly</option>
          </select>
        </label>
        <label>
          Heure
          <input type="time" value={schedule.time} onChange={(event) => patch({ time: event.target.value })} />
        </label>
        {schedule.frequency === "weekly" && (
          <label>
            Jour
            <select value={schedule.dayOfWeek} onChange={(event) => patch({ dayOfWeek: Number(event.target.value) })}>
              {scheduleDays.map((day) => (
                <option value={day.value} key={day.value}>
                  {day.label}
                </option>
              ))}
            </select>
          </label>
        )}
      </div>
    </Panel>
  );
}

function SaveBar({ dirty, saving, onRefresh }: { dirty: boolean; saving: boolean; onRefresh: () => Promise<void> }) {
  return (
    <Panel className="span-3 save-bar">
      <span>{dirty ? "Modifications en attente." : "Aucune modification en attente."}</span>
      <div>
        <button className="ghost-button" type="button" onClick={() => void onRefresh()} disabled={saving}>
          Recharger
        </button>
        <button className="primary-button" type="submit" disabled={!dirty || saving}>
          <Save size={16} />
          {saving ? "Enregistrement" : "Enregistrer"}
        </button>
      </div>
    </Panel>
  );
}

function StatusText({ dirty, loading }: { dirty: boolean; loading: boolean }) {
  if (loading) return <span>chargement</span>;
  return <span>{dirty ? "non enregistre" : "synchronise"}</span>;
}

function LoadingPanel({ label }: { label: string }) {
  return (
    <Panel className="span-3">
      <LoadingState label={label} />
    </Panel>
  );
}
