import type { Database } from 'bun:sqlite';
import { ResponseQueue } from './response-queue';
import { GroupSyncService } from './group-sync';
import { AllowedGroups } from './allowed-groups';
import { Metrics } from './metrics';
import { randomTokenBase64Url } from '../utils/crypto';
import { ICONS } from '../utils/icons';
import { codeId, code, bold, padTaskId } from '../utils/formatting';

type CommandResponse = {
  recipient: string;
  message: string;
  mentions?: string[];
};

/**
 * Construye (si aplica) el DM JIT al creador cuando hay menciones/tokens irrecuperables.
 * Aplica flags y métricas exactamente como en CommandService.
 */
export function buildJitAssigneePrompt(createdBy: string, groupId: string, unresolvedAssigneeDisplays: string[]): CommandResponse[] {
  const responses: CommandResponse[] = [];
  const unresolvedList = Array.from(new Set((unresolvedAssigneeDisplays || []).filter(Boolean)));
  if (unresolvedList.length === 0) return responses;

  const isTest = String(process.env.NODE_ENV || '').toLowerCase() === 'test';
  const enabled = isTest
    ? String(process.env.ONBOARDING_ENABLE_IN_TEST || '').toLowerCase() === 'true'
    : (() => {
      const v = process.env.ONBOARDING_PROMPTS_ENABLED;
      return v == null ? true : ['true', '1', 'yes'].includes(String(v).toLowerCase());
    })();

  const groupLabel = String(groupId && groupId.includes('@g.us') ? groupId : 'dm');
  if (!enabled) {
    try { Metrics.inc('onboarding_prompts_skipped_total', 1, { group_id: groupLabel, source: 'jit_assignee_failure', reason: 'disabled' }); } catch { }
    return responses;
  }

  const bot = String(process.env.CHATBOT_PHONE_NUMBER || '').trim();
  if (!bot || !/^\d+$/.test(bot)) {
    try { Metrics.inc('onboarding_prompts_skipped_total', 1, { group_id: groupLabel, source: 'jit_assignee_failure', reason: 'missing_bot_number' }); } catch { }
    return responses;
  }

  const list = unresolvedList.join(', ');
  let groupCtx = '';
  if (groupId && groupId.includes('@g.us')) {
    const name = GroupSyncService.activeGroupsCache.get(groupId) || groupId;
    groupCtx = ` (en el grupo ${name})`;
  }
  const msg = `No puedo asignar a ${list} aún${groupCtx}. Pídele que toque este enlace y diga 'activar': https://wa.me/${bot}`;
  responses.push({ recipient: createdBy, message: msg });
  try { Metrics.inc('onboarding_prompts_sent_total', 1, { group_id: groupLabel, source: 'jit_assignee_failure' }); } catch { }

  return responses;
}

/**
 * Encola el paquete de 2 DMs de onboarding para miembros del grupo (si aplica).
 * Respeta gating AllowedGroups, cap, cooldown, delays y métricas.
 */
export function maybeEnqueueOnboardingBundle(db: Database, params: {
  gid: string | null;
  createdBy: string;
  assignmentUserIds: string[];
  taskId: number;
  displayCode: number | null;
  description: string;
}): void {
  const isTest = String(process.env.NODE_ENV || '').toLowerCase() === 'test';
  const enabledBase = ['true','1','yes','on'].includes(String(process.env.ONBOARDING_DM_ENABLED || '').toLowerCase());
  const enabled = enabledBase && (!isTest || String(process.env.ONBOARDING_ENABLE_IN_TEST || '').toLowerCase() === 'true');
  const gid = params.gid;

  if (!enabled) {
    try { Metrics.inc('onboarding_dm_skipped_total', 1, { reason: 'disabled', group_id: String(gid || '') }); } catch {}
    return;
  }
  if (!gid) {
    try { Metrics.inc('onboarding_dm_skipped_total', 1, { reason: 'no_group', group_id: '' }); } catch {}
    return;
  }

  // Gating enforce
  let allowed = true;
  try {
    const mode = String(process.env.GROUP_GATING_MODE || 'off').toLowerCase();
    if (mode === 'enforce') {
      try { (AllowedGroups as any).dbInstance = db; } catch {}
      allowed = AllowedGroups.isAllowed(gid);
    }
  } catch {}
  if (!allowed) {
    try { Metrics.inc('onboarding_dm_skipped_total', 1, { reason: 'not_allowed', group_id: String(gid) }); } catch {}
    return;
  }

  const displayCode = params.displayCode;
  if (!(typeof displayCode === 'number' && Number.isFinite(displayCode))) {
    try { Metrics.inc('onboarding_dm_skipped_total', 1, { reason: 'no_display_code', group_id: String(gid) }); } catch {}
    return;
  }

  // Candidatos
  let members = GroupSyncService.listActiveMemberIds(gid);
  const bot = String(process.env.CHATBOT_PHONE_NUMBER || '').trim();
  const exclude = new Set<string>([params.createdBy, ...params.assignmentUserIds]);
  members = members
    .filter(id => /^\d+$/.test(id) && id.length < 14)
    .filter(id => !exclude.has(id))
    .filter(id => !bot || id !== bot);

  if (members.length === 0) {
    try { Metrics.inc('onboarding_dm_skipped_total', 1, { reason: 'no_members', group_id: String(gid) }); } catch {}
    return;
  }

  const capRaw = Number(process.env.ONBOARDING_EVENT_CAP);
  const cap = Number.isFinite(capRaw) && capRaw > 0 ? Math.floor(capRaw) : 30;
  let recipients = members;
  if (recipients.length > cap) {
    try { Metrics.inc('onboarding_recipients_capped_total', recipients.length - cap, { group_id: String(gid) }); } catch {}
    recipients = recipients.slice(0, cap);
  }

  const cooldownRaw = Number(process.env.ONBOARDING_DM_COOLDOWN_DAYS);
  const cooldownDays = Number.isFinite(cooldownRaw) && cooldownRaw >= 0 ? Math.floor(cooldownRaw) : 14;
  const delayEnv = Number(process.env.ONBOARDING_BUNDLE_DELAY_MS);
  const delay2 = Number.isFinite(delayEnv) && delayEnv >= 0 ? Math.floor(delayEnv) : 5000 + Math.floor(Math.random() * 5001); // 5–10s

  const groupLabel = GroupSyncService.activeGroupsCache.get(gid) || gid;
  const codeStr = String(displayCode);
  const desc = (params.description || '(sin descripción)').trim();
  const shortDesc = desc.length > 100 ? (desc.slice(0, 100) + '…') : desc;

  const codeInline = codeId(params.taskId, displayCode);
  const cmdTake = code(`/t tomar ${padTaskId(displayCode)}`);
  const cmdInfo = code(`/t info`);
  const groupBold = bold(`‘${groupLabel}’`);

  const msg1 = `¡Hola!, soy el bot de tareas. En ${groupBold} acaban de crear una tarea: ${codeInline} _${shortDesc}_
- Para hacerte cargo: ${cmdTake}
- Más info: ${cmdInfo}
${ICONS.info} Solo escribo por privado.
${ICONS.info} Cuando reciba tu primer mensaje ya no te enviaré más este recordatorio`;

  const msg2 = `GUÍA RÁPIDA
Puedes interactuar escribiéndome por privado:
- Ver tus tareas: ${code('/t mias')}
- Ver todas: ${code('/t todas')}
- Recibe recordatorios: ${code('/t configurar diario|l-v|semanal|off')}
- Web: ${code('/t web')}`;

  for (const rcpt of recipients) {
    const stats = ResponseQueue.getOnboardingStats(rcpt);
    let variant: 'initial' | 'reminder' | null = null;

    if (!stats || (stats.total || 0) === 0) {
      variant = 'initial';
    } else if (stats.firstInitialAt) {
      let firstMs = NaN;
      try {
        const s = String(stats.firstInitialAt);
        const iso = s.includes('T') ? s : (s.replace(' ', 'T') + 'Z');
        firstMs = Date.parse(iso);
      } catch {}
      const nowMs = Date.now();
      const okCooldown = Number.isFinite(firstMs) ? (nowMs - firstMs) >= cooldownDays * 24 * 60 * 60 * 1000 : false;

      // Interacción del usuario desde el primer paquete
      let hadInteraction = false;
      try {
        const row = db.prepare(`SELECT last_command_at FROM users WHERE id = ?`).get(rcpt) as any;
        const lcRaw = row?.last_command_at ? String(row.last_command_at) : null;
        if (lcRaw) {
          const lcIso = lcRaw.includes('T') ? lcRaw : (lcRaw.replace(' ', 'T') + 'Z');
          const lcMs = Date.parse(lcIso);
          hadInteraction = Number.isFinite(lcMs) && Number.isFinite(firstMs) && lcMs > firstMs;
        }
      } catch {}

      if (okCooldown && !hadInteraction) {
        variant = 'reminder';
      } else {
        try { Metrics.inc('onboarding_dm_skipped_total', 1, { reason: hadInteraction ? 'had_interaction' : 'cooldown_active', group_id: String(gid) }); } catch {}
      }
    }

    if (!variant) continue;

    const bundleId = randomTokenBase64Url(12);
    try {
      ResponseQueue.enqueueOnboarding(rcpt, msg1, { variant, part: 1, bundle_id: bundleId, group_id: gid, task_id: params.taskId, display_code: displayCode }, 0);
      ResponseQueue.enqueueOnboarding(rcpt, msg2, { variant, part: 2, bundle_id: bundleId, group_id: gid, task_id: params.taskId, display_code: displayCode }, delay2);
      try { Metrics.inc('onboarding_bundle_sent_total', 1, { variant, group_id: String(gid) }); } catch {}
    } catch {}
  }
}
