/**
 * Sync input.form / trigger.form fields + ClickUp "Aufgabe erstellen" refs from a selected ClickUp list.
 */

import type { CanvasConnection, CanvasNode } from '../../editor/FlowCanvas';
import type { FormField } from './types';
import { createRef } from './dataRef';

export type ClickUpFieldLike = Record<string, unknown>;

function buildReverseAdjacency(connections: CanvasConnection[]): Record<string, string[]> {
  const rev: Record<string, string[]> = {};
  for (const c of connections) {
    if (!rev[c.targetId]) rev[c.targetId] = [];
    rev[c.targetId].push(c.sourceId);
  }
  return rev;
}

/** Nearest form node upstream (toward triggers) of the ClickUp node. */
export function findClosestUpstreamFormNode(
  targetNodeId: string,
  nodes: CanvasNode[],
  connections: CanvasConnection[]
): CanvasNode | null {
  const nodeById = new Map(nodes.map((n) => [n.id, n]));
  const rev = buildReverseAdjacency(connections);
  const queue: string[] = [...(rev[targetNodeId] ?? [])];
  const visited = new Set<string>();
  while (queue.length > 0) {
    const nid = queue.shift()!;
    if (visited.has(nid)) continue;
    visited.add(nid);
    const n = nodeById.get(nid);
    if (!n) continue;
    if (n.type === 'input.form' || n.type === 'trigger.form') return n;
    for (const p of rev[nid] ?? []) {
      if (!visited.has(p)) queue.push(p);
    }
  }
  return null;
}

export function normalizeClickUpFieldType(raw: unknown): string {
  return String(raw ?? 'short_text')
    .trim()
    .toLowerCase()
    .replace(/-/g, '_')
    .replace(/\s+/g, '_');
}

function linkedListIdFromRelationshipField(field: ClickUpFieldLike): string | null {
  const tc = (field.type_config ?? {}) as Record<string, unknown>;
  const asId = (v: unknown): string | null => {
    if (typeof v === 'string' && v.trim()) return v.trim();
    if (typeof v === 'number' && Number.isFinite(v)) return String(v);
    return null;
  };
  const keys = [
    'linked_list_id',
    'list_id',
    'related_list_id',
    'relationship_list_id',
    'resource_id',
  ];
  for (const k of keys) {
    const raw = tc[k];
    const id = asId(raw);
    if (id) return id;
    if (raw && typeof raw === 'object' && raw !== null) {
      const nested = asId((raw as Record<string, unknown>).id);
      if (nested) return nested;
    }
  }
  const rel = tc.relationship;
  if (rel && typeof rel === 'object' && rel !== null) {
    const r = rel as Record<string, unknown>;
    const fromRel = asId(r.list_id ?? r.id ?? r.target_id ?? r.linked_list_id ?? r.resource_id);
    if (fromRel) return fromRel;
  }
  return null;
}

function fieldUnsupported(ft: string): boolean {
  return ['tasks', 'user', 'users'].includes(ft);
}

function mapCuToInputFormField(
  field: ClickUpFieldLike,
  connectionId: string,
  parentListId: string
): FormField | null {
  const fid = String(field.id ?? '');
  if (!fid) return null;
  const fname = String(field.name ?? fid);
  const ft = normalizeClickUpFieldType(field.type);
  if (fieldUnsupported(ft)) return null;
  const name = `cf_${fid.replace(/[^a-zA-Z0-9_]/g, '_')}`;
  const label = fname || name;

  if (ft === 'list_relationship') {
    const lid = linkedListIdFromRelationshipField(field) ?? parentListId;
    return {
      name,
      label,
      type: 'clickup_tasks',
      required: false,
      clickupConnectionId: connectionId,
      clickupListId: lid,
    };
  }
  if (
    ft === 'drop_down' ||
    ft === 'dropdown' ||
    ft === 'text' ||
    ft === 'long_text' ||
    ft === 'short_text' ||
    ft === 'email' ||
    ft === 'phone' ||
    ft === 'url'
  ) {
    return { name, label, type: 'string', required: false };
  }
  if (ft === 'number' || ft === 'currency') {
    return { name, label, type: 'number', required: false };
  }
  if (ft === 'date') {
    return { name, label, type: 'date', required: false };
  }
  if (ft === 'checkbox') {
    return { name, label, type: 'boolean', required: false };
  }
  return { name, label, type: 'string', required: false };
}

/** trigger.form row; `clickup_status` carries options from the same list API as the ClickUp node dropdown. */
export type TriggerFormFieldRow = {
  name: string;
  label: string;
  type: 'text' | 'number' | 'email' | 'date' | 'boolean' | 'clickup_status';
  statusOptions?: Array<{ value: string; label: string }>;
};

function mapCuToTriggerFormField(field: ClickUpFieldLike, _connectionId: string, _parentListId: string): TriggerFormFieldRow | null {
  const fid = String(field.id ?? '');
  if (!fid) return null;
  const fname = String(field.name ?? fid);
  const ft = normalizeClickUpFieldType(field.type);
  if (fieldUnsupported(ft)) return null;
  const name = `cf_${fid.replace(/[^a-zA-Z0-9_]/g, '_')}`;
  const label = fname || name;
  if (ft === 'list_relationship') {
    return { name, label, type: 'text' };
  }
  if (ft === 'number' || ft === 'currency') {
    return { name, label, type: 'number' };
  }
  if (ft === 'date') {
    return { name, label, type: 'date' };
  }
  if (ft === 'checkbox') {
    return { name, label, type: 'boolean' };
  }
  if (ft === 'email') {
    return { name, label, type: 'email' };
  }
  return { name, label, type: 'text' };
}

export const PAYLOAD_TITLE = 'title';
export const PAYLOAD_DESCRIPTION = 'description';
export const PAYLOAD_STATUS = 'clickup_status';
export const PAYLOAD_PRIORITY = 'clickup_priority';
export const PAYLOAD_DUE = 'clickup_due_date';
export const PAYLOAD_TIME_H = 'clickup_time_estimate_h';

/** Same ordering as ClickUp list `statuses` (GET /list/{id}). */
export function statusOptionsFromListStatuses(
  listStatuses: Array<{ status: string; orderindex: number }>
): Array<{ value: string; label: string }> {
  return [...listStatuses]
    .sort((a, b) => a.orderindex - b.orderindex)
    .map((s) => ({ value: s.status, label: s.status }));
}

export interface SyncFromListResult {
  inputFormFields: FormField[];
  triggerFormFields: TriggerFormFieldRow[];
  clickupPatch: Record<string, unknown>;
}

/**
 * Build form field rows + ClickUp createTask parameter patch (refs → payload.*).
 */
export function buildSyncFromClickUpList(args: {
  formNodeId: string;
  listFields: ClickUpFieldLike[];
  /** From GET /list/{id} → list.statuses (same source as the ClickUp node status dropdown). */
  listStatuses: Array<{ status: string; orderindex: number }>;
  connectionId: string;
  teamId: string;
  listId: string;
}): SyncFromListResult {
  const { formNodeId, listFields, listStatuses, connectionId, teamId, listId } = args;
  const ref = (key: string) => createRef(formNodeId, ['payload', key]);

  const statusOpts = statusOptionsFromListStatuses(listStatuses);

  const standardInput: FormField[] = [
    { name: PAYLOAD_TITLE, label: 'Titel', type: 'string', required: true },
    { name: PAYLOAD_DESCRIPTION, label: 'Beschreibung', type: 'string', required: false },
    ...(statusOpts.length > 0
      ? [
          {
            name: PAYLOAD_STATUS,
            label: 'Status',
            type: 'clickup_status',
            required: false,
            clickupStatusOptions: statusOpts,
          } as FormField,
        ]
      : []),
    { name: PAYLOAD_PRIORITY, label: 'Priorität (1–4)', type: 'number', required: false },
    { name: PAYLOAD_DUE, label: 'Fälligkeit', type: 'date', required: false },
    { name: PAYLOAD_TIME_H, label: 'Zeitschätzung (Stunden)', type: 'number', required: false },
  ];

  const statusTriggerRow: TriggerFormFieldRow | null =
    statusOpts.length > 0
      ? {
          name: PAYLOAD_STATUS,
          label: 'Status',
          type: 'clickup_status',
          statusOptions: statusOpts,
        }
      : null;

  const standardTrigger: TriggerFormFieldRow[] = [
    { name: PAYLOAD_TITLE, label: 'Titel', type: 'text' },
    { name: PAYLOAD_DESCRIPTION, label: 'Beschreibung', type: 'text' },
    ...(statusTriggerRow ? [statusTriggerRow] : []),
    { name: PAYLOAD_PRIORITY, label: 'Priorität (1–4)', type: 'number' },
    { name: PAYLOAD_DUE, label: 'Fälligkeit', type: 'date' },
    { name: PAYLOAD_TIME_H, label: 'Zeitschätzung (Stunden)', type: 'number' },
  ];
  if (statusOpts.length > 0) {
    standardTrigger.splice(2, 0, {
      name: PAYLOAD_STATUS,
      label: 'Status',
      type: 'clickup_status',
      statusOptions: statusOpts,
    });
  }

  const customInput: FormField[] = [];
  const customTrigger: TriggerFormFieldRow[] = [];
  const customRefs: Record<string, unknown> = {};

  for (const f of listFields) {
    if (!f || typeof f !== 'object') continue;
    const inf = mapCuToInputFormField(f as ClickUpFieldLike, connectionId, listId);
    const tr = mapCuToTriggerFormField(f as ClickUpFieldLike, connectionId, listId);
    if (inf) customInput.push(inf);
    if (tr) customTrigger.push(tr);
    const fid = String((f as ClickUpFieldLike).id ?? '');
    const payloadKey = inf?.name;
    if (fid && payloadKey) {
      customRefs[fid] = createRef(formNodeId, ['payload', payloadKey]);
    }
  }

  const inputFormFields = [...standardInput, ...customInput];
  const triggerFormFields = [...standardTrigger, ...customTrigger];

  const clickupPatch: Record<string, unknown> = {
    connectionId,
    teamId,
    listId,
    path: `/team/${teamId}/list/${listId}`,
    name: ref(PAYLOAD_TITLE),
    description: ref(PAYLOAD_DESCRIPTION),
    taskPriority: ref(PAYLOAD_PRIORITY),
    taskDueDateMs: ref(PAYLOAD_DUE),
    taskTimeEstimateHours: ref(PAYLOAD_TIME_H),
  };
  if (statusOpts.length > 0) {
    clickupPatch.taskStatus = ref(PAYLOAD_STATUS);
  }
  if (Object.keys(customRefs).length) {
    clickupPatch.customFieldValues = customRefs;
  }

  return { inputFormFields, triggerFormFields, clickupPatch };
}
