/**
 * Utilidades compartidas para handlers de comandos (Etapa 1).
 * Aún no se usan desde CommandService; servirán en etapas siguientes.
 */

import { TaskService } from '../../tasks/service';
import { GroupSyncService } from '../group-sync';
import { ICONS } from '../../utils/icons';
import { codeId, formatDDMM } from '../../utils/formatting';

export const ACTION_ALIASES: Record<string, string> = {
  'n': 'nueva',
  'nueva': 'nueva',
  'crear': 'nueva',
  '+': 'nueva',
  'ver': 'ver',
  'mostrar': 'ver',
  'listar': 'ver',
  'ls': 'ver',
  'mias': 'ver',
  'mías': 'ver',
  'todas': 'ver',
  'todos': 'ver',
  'x': 'completar',
  'hecho': 'completar',
  'completar': 'completar',
  'done': 'completar',
  'tomar': 'tomar',
  'claim': 'tomar',
  'asumir': 'tomar',
  'asumo': 'tomar',
  'soltar': 'soltar',
  'unassign': 'soltar',
  'dejar': 'soltar',
  'liberar': 'soltar',
  'renunciar': 'soltar',
  'ayuda': 'ayuda',
  'help': 'ayuda',
  'info': 'ayuda',
  '?': 'ayuda',
  'config': 'alarma',
  'configurar': 'alarma',
  'alarma': 'alarma',
  'recordatorio': 'alarma',
  'web': 'web'
};

export const SCOPE_ALIASES: Record<string, 'mis' | 'todos'> = {
  'todo': 'todos',
  'todos': 'todos',
  'todas': 'todos',
  'mis': 'mis',
  'mias': 'mis',
  'mías': 'mis',
  'yo': 'mis'
};

export const CTA_HELP = 'ℹ️ Tus tareas: `t mias` · Todas: `t todas` · Info: `t info` · Web: `t web`';

/**
 * Formatea un Date a YYYY-MM-DD respetando TZ (por defecto Europe/Madrid).
 */
function ymdInTZ(d: Date, tz?: string): string {
  const TZ = (tz && tz.trim()) || (process.env.TZ && process.env.TZ.trim()) || 'Europe/Madrid';
  const parts = new Intl.DateTimeFormat('en-GB', {
    timeZone: TZ,
    year: 'numeric',
    month: '2-digit',
    day: '2-digit'
  }).formatToParts(d);
  const get = (t: string) => parts.find(p => p.type === t)?.value || '';
  return `${get('year')}-${get('month')}-${get('day')}`;
}

export function todayYMD(tz?: string): string {
  return ymdInTZ(new Date(), tz);
}

/**
 * Parsea múltiples IDs desde tokens, deduplica, y aplica límite.
 */
export function parseMultipleIds(tokens: string[], max: number = 10): { ids: number[]; truncated: boolean } {
  const raw = (tokens || []).join(' ').trim();
  const all = raw
    ? raw
        .split(/[,\s]+/)
        .map(t => t.trim())
        .filter(Boolean)
        .map(t => parseInt(t, 10))
        .filter(n => Number.isFinite(n) && n > 0)
    : [];
  const dedup: number[] = [];
  const seen = new Set<number>();
  for (const n of all) {
    if (!seen.has(n)) {
      seen.add(n);
      dedup.push(n);
    }
  }
  const truncated = dedup.length > max;
  const ids = dedup.slice(0, max);
  return { ids, truncated };
}

/**
 * Resuelve un ID de entrada (display_code) a task.id si está activa.
 */
export function resolveTaskIdFromInput(n: number): number | null {
  const byCode = TaskService.getActiveTaskByDisplayCode(n);
  return byCode ? byCode.id : null;
}

/**
 * Aplica la política de membresía para acciones sobre una tarea.
 * Devuelve true si el usuario está permitido según flags/env.
 */
export function enforceMembership(sender: string, task: { group_id?: string | null }, enforceFlag?: boolean): boolean {
  const enforce =
    typeof enforceFlag === 'boolean'
      ? enforceFlag
      : String(process.env.GROUP_MEMBERS_ENFORCE || '').toLowerCase() === 'true';

  const gid = task?.group_id || null;
  if (!gid) return true; // tareas personales no requieren membresía
  if (!enforce) return true;
  if (!GroupSyncService.isSnapshotFresh(gid)) return true;

  return GroupSyncService.isUserActiveInGroup(sender, gid);
}

/** Formatea el sufijo de fecha de vencimiento para una respuesta de tarea. */
export function formatDue(task: { due_date?: string | null } | null | undefined): string {
  return task?.due_date ? ` — ${ICONS.date} ${formatDDMM(task.due_date)}` : '';
}

/** Construye el texto de resumen para procesamiento por lotes. */
export function buildSummary(counts: Record<string, number>, labels: Record<string, string>): string {
  const parts: string[] = [];
  for (const key of Object.keys(counts)) {
    if (counts[key]) parts.push(`${labels[key]} ${counts[key]}`);
  }
  return parts.length ? `Resumen: ${parts.join(', ')}.` : '';
}

/** Construye el fragmento " — ⚠️ 📅 DD/MM" o vacío para una tarea según si está vencida. */
export function formatDatePart(due_date: string | null | undefined, todayYMD: string): string {
  if (!due_date) return '';
  const overdue = due_date < todayYMD;
  return ` — ${overdue ? `${ICONS.warn} ` : ''}${ICONS.date} ${formatDDMM(due_date)}`;
}

/** Renderiza una línea de tarea con su código, descripción, fecha y dueño. */
export function formatTaskLine(
  t: { id: number; description?: string | null; due_date?: string | null; display_code?: number | null },
  owner: string,
  todayYMD: string
): string {
  const dc = (t as any).display_code as number | undefined;
  const datePart = formatDatePart(t.due_date, todayYMD);
  return `- ${codeId(t.id, dc)} ${t.description || '(sin descripción)'}${datePart} — ${owner}`;
}

/** Outcome of a single action in a multi-ID batch. */
export interface BatchOutcome {
  status: string;
  line: string;
}

/**
 * Generic multi-ID batch handler.
 *
 * Iterates over IDs, calls `action` for each, collects outcomes,
 * counts statuses, builds a summary and returns a single Msg.
 */
export function handleBatch(
  sender: string,
  ids: number[],
  truncated: boolean,
  action: (idInput: number, sender: string) => BatchOutcome,
  statusLabels: Record<string, string>,
  usageMessage: string,
): { recipient: string; message: string }[] {
  if (ids.length === 0) {
    return [{ recipient: sender, message: usageMessage }];
  }

  const lines: string[] = [];
  if (truncated) lines.push('⚠️ Se procesarán solo los primeros 10 IDs.');

  const counts: Record<string, number> = {};

  for (const idInput of ids) {
    const outcome = action(idInput, sender);
    lines.push(outcome.line);
    counts[outcome.status] = (counts[outcome.status] || 0) + 1;
  }

  const summary = buildSummary(counts, statusLabels);
  if (summary) { lines.push(''); lines.push(summary); }

  return [{ recipient: sender, message: lines.join('\n') }];
}

/** Resuelve un ID de entrada, carga la tarea y aplica membresía. Retorna error o {resolvedId, task}. */
export function resolveAndValidate(
  idInput: number,
  sender: string
): { resolvedId: number; task: any } | { error: string } {
  const resolvedId = resolveTaskIdFromInput(idInput);
  if (!resolvedId) return { error: `⚠️ Tarea ${codeId(idInput)} no encontrada.` };
  const task = TaskService.getTaskById(resolvedId);
  if (!task) return { error: `⚠️ Tarea ${codeId(resolvedId)} no encontrada.` };
  if (!enforceMembership(sender, task)) return { error: `🚫 ${codeId(resolvedId)} — no permitido (no eres miembro activo).` };
  return { resolvedId, task };
}
