import { useEffect, useRef, useState, type ReactNode } from 'react';

import type { InstanceContext } from '../app-shell.js';

/** Aggregate task counts only; per-task records and configuration are intentionally unsupported. */
export interface AutomationTaskCounts {
  readonly total?: number | null;
  readonly enabled?: number | null;
  readonly disabled?: number | null;
  readonly running?: number | null;
  readonly queued?: number | null;
  readonly succeeded?: number | null;
  readonly failed?: number | null;
}

/** Bounded high-level status labels only, never status payloads or raw logs. */
export type AutomationState = 'healthy' | 'degraded' | 'failed' | 'disabled' | 'unknown';
export type AutomationScheduler = 'active' | 'idle' | 'paused' | 'disabled' | 'unavailable';
export type AutomationWorkers = 'available' | 'busy' | 'degraded' | 'disabled' | 'unavailable';
export interface AutomationStatus {
  readonly state?: AutomationState | null;
  readonly scheduler?: AutomationScheduler | null;
  readonly workers?: AutomationWorkers | null;
}

export interface AutomationSnapshot {
  readonly observedAt?: string;
  readonly status: AutomationStatus;
  readonly tasks: AutomationTaskCounts;
}

export interface AutomationDataSource {
  /** Injected by the authenticated owner; this isolated module defines no production endpoint. */
  load(instanceId: string, signal: AbortSignal): Promise<unknown>;
}

export interface AutomationModuleProps {
  readonly instance: InstanceContext;
  readonly dataSource?: AutomationDataSource;
  readonly refreshSignal?: unknown;
}

type ReadState =
  | { kind: 'idle'; ownerId: string }
  | { kind: 'loading'; ownerId: string; snapshot?: AutomationSnapshot }
  | { kind: 'ready'; ownerId: string; snapshot: AutomationSnapshot }
  | { kind: 'error'; ownerId: string; snapshot?: AutomationSnapshot };

const SAFE_LOAD_ERROR = 'Automation data could not be loaded.';
const STATES = new Set<AutomationState>(['healthy', 'degraded', 'failed', 'disabled', 'unknown']);
const SCHEDULERS = new Set<AutomationScheduler>([
  'active',
  'idle',
  'paused',
  'disabled',
  'unavailable',
]);
const WORKERS = new Set<AutomationWorkers>([
  'available',
  'busy',
  'degraded',
  'disabled',
  'unavailable',
]);
const TASK_COUNT_KEYS = [
  'total',
  'enabled',
  'disabled',
  'running',
  'queued',
  'succeeded',
  'failed',
] as const;

function isRecord(value: unknown): value is Readonly<Record<string, unknown>> {
  return typeof value === 'object' && value !== null && !Array.isArray(value);
}

function safeTimestamp(value: unknown): string | undefined {
  if (
    typeof value !== 'string' ||
    !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z$/.test(value)
  )
    return undefined;
  const parsed = new Date(value);
  if (!Number.isFinite(parsed.getTime())) return undefined;
  const canonical = parsed.toISOString();
  return canonical === value || canonical === value.replace(/Z$/, '.000Z') ? value : undefined;
}

function boundedEnum<T extends string>(
  value: unknown,
  allowed: ReadonlySet<T>,
): T | null | undefined {
  if (value === null) return null;
  return typeof value === 'string' && allowed.has(value as T) ? (value as T) : undefined;
}

/** Copy and validate untrusted source data before it can enter React state. */
export function sanitizeAutomationSnapshot(value: unknown): AutomationSnapshot {
  const source = isRecord(value) ? value : {};
  const rawStatus = isRecord(source.status) ? source.status : {};
  const state = boundedEnum(rawStatus.state, STATES);
  const scheduler = boundedEnum(rawStatus.scheduler, SCHEDULERS);
  const workers = boundedEnum(rawStatus.workers, WORKERS);
  const status: AutomationStatus = {
    ...(state !== undefined ? { state } : {}),
    ...(scheduler !== undefined ? { scheduler } : {}),
    ...(workers !== undefined ? { workers } : {}),
  };
  const rawTasks = isRecord(source.tasks) ? source.tasks : {};
  const tasks: Record<string, number | null> = {};
  for (const key of TASK_COUNT_KEYS) {
    const count = rawTasks[key];
    if (count === null || (Number.isSafeInteger(count) && (count as number) >= 0))
      tasks[key] = count as number | null;
  }
  const observedAt = safeTimestamp(source.observedAt);
  return {
    ...(observedAt ? { observedAt } : {}),
    status,
    tasks,
  };
}

function Section({ label, children }: { label: string; children: ReactNode }) {
  return (
    <section className="automation-card" aria-label={label}>
      <h2>{label}</h2>
      {children}
    </section>
  );
}

function Fields({
  values,
}: {
  values: readonly (readonly [string, string | number | null | undefined])[];
}) {
  const supplied = values.filter(([, value]) => value !== undefined);
  if (!supplied.length) return <p>No aggregate status was supplied.</p>;
  return (
    <dl>
      {supplied.map(([label, value]) => (
        <div key={label}>
          <dt>{label}</dt>
          <dd>{value == null ? 'Unavailable' : String(value)}</dd>
        </div>
      ))}
    </dl>
  );
}

function SnapshotView({ snapshot }: { snapshot: AutomationSnapshot }) {
  const status = snapshot.status;
  const tasks = snapshot.tasks;
  return (
    <>
      {snapshot.observedAt ? <p>Observed {snapshot.observedAt}</p> : null}
      <p>Read-only aggregate view; task details and operational controls are excluded.</p>
      <div className="automation-grid">
        <Section label="Automation status">
          <Fields
            values={[
              ['State', status.state],
              ['Scheduler', status.scheduler],
              ['Workers', status.workers],
            ]}
          />
        </Section>
        <Section label="Task counts">
          <Fields
            values={[
              ['Total', tasks.total],
              ['Enabled', tasks.enabled],
              ['Disabled', tasks.disabled],
              ['Running', tasks.running],
              ['Queued', tasks.queued],
              ['Succeeded', tasks.succeeded],
              ['Failed', tasks.failed],
            ]}
          />
        </Section>
      </div>
    </>
  );
}

export function AutomationModule({ instance, dataSource, refreshSignal }: AutomationModuleProps) {
  const requestFence = useRef(0);
  const [retry, setRetry] = useState(0);
  const [state, setState] = useState<ReadState>({ kind: 'idle', ownerId: instance.id });

  useEffect(() => {
    const request = ++requestFence.current;
    const ownerId = instance.id;
    const controller = new AbortController();

    if (instance.authentication !== 'authenticated' || !dataSource) {
      setState({ kind: 'idle', ownerId });
      return () => controller.abort();
    }

    setState((current) => ({
      kind: 'loading',
      ownerId,
      ...(current.ownerId === ownerId && current.kind !== 'idle' && current.snapshot
        ? { snapshot: current.snapshot }
        : {}),
    }));

    let read: Promise<unknown>;
    try {
      read = dataSource.load(ownerId, controller.signal);
    } catch (reason: unknown) {
      read = Promise.reject(reason);
    }
    void read.then(
      (snapshot) => {
        if (request === requestFence.current && !controller.signal.aborted)
          setState({ kind: 'ready', ownerId, snapshot: sanitizeAutomationSnapshot(snapshot) });
      },
      (_reason: unknown) => {
        void _reason;
        if (request === requestFence.current && !controller.signal.aborted)
          setState((current) => ({
            kind: 'error',
            ownerId,
            ...(current.ownerId === ownerId && current.kind === 'loading' && current.snapshot
              ? { snapshot: current.snapshot }
              : {}),
          }));
      },
    );
    return () => controller.abort();
  }, [dataSource, instance.authentication, instance.id, refreshSignal, retry]);

  if (instance.authentication !== 'authenticated')
    return (
      <div className="state-panel state-error" role="alert">
        Authentication is required before Automation data can be read for this instance.
      </div>
    );

  if (!dataSource)
    return (
      <div className="state-panel" role="status" aria-label="Automation unavailable">
        No safe Automation read data source is available. This console will not invent or call an
        uncontracted production endpoint.
      </div>
    );

  const retained =
    state.ownerId === instance.id && (state.kind === 'loading' || state.kind === 'error')
      ? state.snapshot
      : undefined;
  if ((state.kind === 'idle' || state.kind === 'loading') && !retained)
    return (
      <p role="status" aria-label="Automation loading status">
        Loading Automation…
      </p>
    );

  if (state.kind === 'error' && !retained)
    return (
      <div className="state-panel state-error" role="alert">
        <p>Unable to load Automation: {SAFE_LOAD_ERROR}</p>
        <button type="button" onClick={() => setRetry((value) => value + 1)}>
          Retry loading Automation
        </button>
      </div>
    );

  const snapshot =
    state.kind === 'ready' && state.ownerId === instance.id ? state.snapshot : retained;
  if (!snapshot) return null;
  return (
    <div className="automation-module">
      {state.kind === 'loading' ? <p role="status">Refreshing Automation…</p> : null}
      {state.kind === 'error' ? (
        <div className="state-panel state-error" role="alert">
          <p>Refresh failed; showing the last known Automation data.</p>
          <button type="button" onClick={() => setRetry((value) => value + 1)}>
            Retry loading Automation
          </button>
        </div>
      ) : null}
      {instance.freshness !== 'fresh' ? (
        <p className="state-panel" role="status" aria-label="Automation freshness">
          Automation data is {instance.freshness}; verify freshness before relying on these values.
        </p>
      ) : null}
      <SnapshotView snapshot={snapshot} />
    </div>
  );
}
