import { useMemo, useState } from 'react';
import { CheckCircle2 } from 'lucide-react';
import { Button } from '../core/Button';
import { Input } from '../core/Input';
import { Select } from '../core/Select';
import { MultiSelect } from '../core/MultiSelect';
import { LookupField } from './LookupField';
import type { LookupValue } from './LookupField';
import { useZino } from '../../api/provider';
import type { ActivityDef, FieldDef } from '../../api/forms';
import type { LeadRecord } from '../../api/types';
import type { ActivityResult } from '../../api/types';

export interface ActivityFormProps {
  def: ActivityDef;
  /** Omit for the INIT activity (Capture Lead) — submits via /start. */
  instanceId?: number | string;
  /** Seed values from an existing record. */
  record?: LeadRecord | null;
  onSuccess?: (res: ActivityResult) => void;
  /** Override the green confirmation line. */
  successMessage?: string;
}

// datetime-local ("YYYY-MM-DDTHH:MM") → RFC 3339 with local TZ offset, the
// format the workflow engine validates datetime fields against.
function toRfc3339(local: string): string {
  const d = new Date(local);
  if (Number.isNaN(d.getTime())) return local;
  const pad = (n: number) => String(n).padStart(2, '0');
  const off = -d.getTimezoneOffset();
  const sign = off >= 0 ? '+' : '-';
  const abs = Math.abs(off);
  return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}${sign}${pad(Math.floor(abs / 60))}:${pad(abs % 60)}`;
}

function seedFor(field: FieldDef, record?: LeadRecord | null): unknown {
  const key = field.seedKey ?? field.id.replace(/_input$/, '');
  const fromRecord = record ? (record as Record<string, unknown>)[key] : undefined;
  if (fromRecord !== undefined && fromRecord !== null) return fromRecord;
  switch (field.type) {
    case 'multiselect':
      return [];
    case 'boolean':
      return false;
    default:
      return '';
  }
}

/** Renders an activity's fields from its declarative spec and submits via
 *  performActivity (or startInstance when no instanceId is given). */
export function ActivityForm({ def, instanceId, record, onSuccess, successMessage }: ActivityFormProps) {
  const { client } = useZino();
  const [values, setValues] = useState<Record<string, unknown>>(() => {
    const init: Record<string, unknown> = {};
    def.fields.forEach((f) => (init[f.id] = seedFor(f, record)));
    return init;
  });
  const [submitting, setSubmitting] = useState(false);
  const [result, setResult] = useState<{ ok: boolean; msg: string } | null>(null);

  const set = (id: string, v: unknown) => setValues((p) => ({ ...p, [id]: v }));

  const missing = useMemo(
    () =>
      def.fields.filter((f) => {
        if (!f.required) return false;
        const v = values[f.id];
        if (Array.isArray(v)) return v.length === 0;
        return v === '' || v === null || v === undefined;
      }),
    [def.fields, values],
  );

  async function submit() {
    if (missing.length) {
      setResult({ ok: false, msg: `Fill required: ${missing.map((m) => m.label).join(', ')}` });
      return;
    }
    setSubmitting(true);
    setResult(null);

    // Drop empty optional values so we don't overwrite with blanks.
    const data: Record<string, unknown> = {};
    for (const f of def.fields) {
      const v = values[f.id];
      if (v === '' || v === null || v === undefined) continue;
      if (Array.isArray(v) && v.length === 0) continue;
      data[f.id] =
        f.type === 'number' ? Number(v) || 0 : f.type === 'datetime' ? toRfc3339(String(v)) : v;
    }

    try {
      const res =
        instanceId != null
          ? await client.performActivity(instanceId, def.uid, data)
          : await client.startInstance(def.uid, data);
      setResult({ ok: true, msg: successMessage ?? `${def.name} ${def.done}.` });
      onSuccess?.(res);
    } catch (e) {
      setResult({ ok: false, msg: e instanceof Error ? e.message : ((e as { message?: string })?.message ?? 'Submit failed') });
    } finally {
      setSubmitting(false);
    }
  }

  return (
    <div className="flex flex-col gap-4">
      <div className="grid grid-cols-2 gap-4">
        {def.fields.map((f) => (
          <Field
            key={f.id}
            field={f}
            value={values[f.id]}
            onChange={(v) => set(f.id, v)}
            activityId={def.uid}
            instanceId={instanceId}
          />
        ))}
      </div>

      {result && (
        <div
          className={
            result.ok
              ? 'flex items-center gap-2 text-sm text-emerald-700 bg-emerald-100 border border-emerald-300 rounded-md px-4 py-3'
              : 'text-sm text-amber-700 bg-escalated-soft border border-amber-300 rounded-md px-4 py-3'
          }
        >
          {result.ok && <CheckCircle2 size={16} />}
          {result.msg}
        </div>
      )}

      <div>
        <Button variant="primary" disabled={submitting || result?.ok} onClick={submit}>
          {submitting ? 'Submitting…' : result?.ok ? 'Done' : def.submitLabel}
        </Button>
      </div>
    </div>
  );
}

function Field({
  field,
  value,
  onChange,
  activityId,
  instanceId,
}: {
  field: FieldDef;
  value: unknown;
  onChange: (v: unknown) => void;
  activityId: string;
  instanceId?: number | string;
}) {
  const full = field.type === 'longtext' || field.type === 'multiselect' || field.type === 'lookup';
  const wrap = full ? 'col-span-full' : '';

  switch (field.type) {
    case 'longtext':
      return (
        <label className={`${wrap} flex flex-col gap-1.5`}>
          <span className="text-sm font-medium text-muted">
            {field.label}
            {field.required && <span className="text-ruby-600"> *</span>}
          </span>
          <textarea
            rows={3}
            value={String(value ?? '')}
            onChange={(e) => onChange(e.target.value)}
            placeholder={field.placeholder}
            className="font-sans text-base text-strong border border-border-default rounded-md px-3 py-2.5 resize-y outline-none focus:border-sunrise-500"
          />
        </label>
      );

    case 'select':
      return (
        <Select
          label={field.label}
          required={field.required}
          value={String(value ?? '')}
          onChange={(e) => onChange(e.target.value)}
          options={[{ value: '', label: field.required ? 'Select…' : '— None —' }, ...(field.options ?? [])]}
        />
      );

    case 'multiselect':
      return (
        <div className={wrap}>
          <MultiSelect
            label={field.label}
            value={Array.isArray(value) ? (value as string[]) : []}
            onChange={onChange}
            options={field.options ?? []}
          />
        </div>
      );

    case 'boolean':
      return (
        <label className="flex items-center gap-2.5 h-[42px] mt-6 cursor-pointer select-none">
          <input
            type="checkbox"
            checked={!!value}
            onChange={(e) => onChange(e.target.checked)}
            className="w-4 h-4 accent-sunrise-500"
          />
          <span className="text-sm font-medium text-body">{field.label}</span>
        </label>
      );

    case 'lookup':
      return (
        <div className={wrap}>
          <LookupField
            label={field.label}
            required={field.required}
            templateUid={field.lookupTemplate!}
            displayCols={field.lookupDisplay ?? []}
            storageCols={field.lookupStorage ?? []}
            activityId={activityId}
            fieldId={field.id}
            instanceId={instanceId}
            value={(value as LookupValue) ?? null}
            onChange={onChange}
          />
        </div>
      );

    default: {
      const htmlType =
        field.type === 'number'
          ? 'number'
          : field.type === 'date'
            ? 'date'
            : field.type === 'datetime'
              ? 'datetime-local'
              : field.type === 'email'
                ? 'email'
                : field.type === 'phone'
                  ? 'tel'
                  : 'text';
      return (
        <Input
          label={field.label}
          required={field.required}
          type={htmlType}
          prefix={field.prefix}
          placeholder={field.placeholder}
          value={String(value ?? '')}
          onChange={(e) => onChange(e.target.value)}
        />
      );
    }
  }
}
