/**
 * groupForm.js — Onboarding form flow for WhatsApp groups
 *
 * Asks profile questions one at a time to the client.
 * - email, full_name          → pre-filled from career-strategy.json
 * - phone, address, dob, linkedin → pre-filled from CV (if available) or group.json
 * - interested_in_ai          → skipped automatically if used_ai_tools = yes
 *
 * Extracts answers via regex (emails/phones/URLs) or AI classification.
 * Tracks progress in mentees/{slug}/form.json
 * On completion → triggers Career Plan generation.
 */

import { existsSync, readFileSync, writeFileSync } from 'fs';
import { join } from 'path';

function appendGroupMsg(scriptDir, slug, role, text) {
  const p = join(scriptDir, 'mentees', slug, 'group-chat.json');
  let msgs = [];
  if (existsSync(p)) {
    try { msgs = JSON.parse(readFileSync(p, 'utf8')); } catch {}
  }
  msgs.push({ role, text, ts: new Date().toISOString() });
  writeFileSync(p, JSON.stringify(msgs, null, 2));
}

// ── Question set ───────────────────────────────────────────────────────────────

export const QUESTIONS = [
  { key: 'current_position',         en: 'What is your current (or most recent) job title?' },
  { key: 'current_area',             en: 'What is your current area of work?' },
  { key: 'annual_bonus',             en: 'Do you receive an annual bonus? If so, roughly how much?' },
  { key: 'desired_area',             en: 'Which area would you like to move your career into?' },
  { key: 'preferred_sectors',        en: 'Which sectors do you prefer to work in? (e.g. Tech, Finance, Industrial — not limiting, just a preference)' },
  { key: 'preferred_companies',      en: 'Are there any specific companies you would like to target? (optional — say "none" if not)' },
  { key: 'open_roles',               en: 'Besides your main target role, what other job titles would you consider? (e.g. Senior HR Manager, Head of People)' },
  { key: 'desired_salary',           en: 'What is your target gross annual salary?' },
  { key: 'date_of_birth',            en: 'What is your date of birth? (helps us calibrate the seniority of roles)' },
  { key: 'address',                  en: 'What is your full address? (used to find nearby opportunities and pre-fill job applications)' },
  { key: 'phone',                    en: 'What is your phone number including country code?' },
  { key: 'linkedin_url',             en: 'What is the link to your LinkedIn profile?' },
  { key: 'nationality',              en: 'What is your nationality?' },
  { key: 'relocation_remote',        en: 'Are you open to relocating or working remotely?' },
  { key: 'professional_goal_6_12m',  en: 'Where do you want to be professionally in the next 6–12 months?' },
  { key: 'biggest_challenge',        en: 'What is your biggest career challenge right now?' },
  { key: 'updated_cv',               en: 'Do you have an up-to-date CV?' },
  { key: 'linkedin_updated',         en: 'Have you recently updated your LinkedIn profile?' },
  { key: 'professional_perception',  en: 'How would you like to be perceived professionally?' },
  { key: 'used_ai_tools',            en: 'Have you ever used AI tools (like ChatGPT) for your career?' },
  {
    key: 'interested_in_ai',
    en: 'Are you interested in exploring digital and AI tools as part of your career process?',
    skipIf: (answers) => /yes|yeah|yep|oui|sim|sí|every|always|daily|regular|tout|todos|claro/i.test(answers.used_ai_tools || ''),
  },
  { key: 'interview_confidence',     en: 'How confident do you feel in job interviews?' },
  { key: 'salary_negotiation',       en: 'Have you ever struggled to negotiate salary or stand out in selection processes?' },
  { key: 'weekly_hours',             en: 'How many hours per week can you dedicate to your job hunting process (applications, prep, networking)?' },
  { key: 'additional_notes',         en: 'Is there anything else you\'d like to share to help us support you better?' },
  { key: 'target_applications_week', en: 'How many job applications are you currently sending per week on average (if any)? And how many are you aiming to send?' },
  { key: 'preferred_company_type',   en: 'What type of company do you prefer? (startup, large corporate, remote-first, public sector…)' },
  { key: 'job_search_start_date',    en: 'When do you want to start applying actively?' },
];

// ── Form state helpers ─────────────────────────────────────────────────────────

export function loadForm(scriptDir, slug) {
  const p = join(scriptDir, 'mentees', slug, 'form.json');
  if (!existsSync(p)) return { startedAt: null, completedAt: null, currentIndex: 0, answers: {} };
  try { return JSON.parse(readFileSync(p, 'utf8')); }
  catch { return { startedAt: null, completedAt: null, currentIndex: 0, answers: {} }; }
}

export function saveForm(scriptDir, slug, form) {
  const p = join(scriptDir, 'mentees', slug, 'form.json');
  writeFileSync(p, JSON.stringify(form, null, 2));
}

export function isFormComplete(form) {
  return form.completedAt !== null;
}

// ── Skip logic ─────────────────────────────────────────────────────────────────

/**
 * Find the next question index that should be asked.
 * Skips questions that are already answered (pre-filled or previously answered)
 * and questions whose skipIf condition is met.
 */
function nextUnansweredIndex(fromIndex, answers) {
  let i = fromIndex;
  while (i < QUESTIONS.length) {
    const q = QUESTIONS[i];
    if (answers[q.key]) { i++; continue; }        // already answered
    if (q.skipIf?.(answers)) {
      answers[q.key] = '__skipped__';              // mark so it won't be re-evaluated
      i++;
      continue;
    }
    break;
  }
  return i;
}

// ── Answer extraction ──────────────────────────────────────────────────────────

function extractDirect(key, text) {
  switch (key) {
    case 'email':
    case 'professional_email': {
      const m = text.match(/[\w.+-]+@[\w-]+\.[a-z]{2,}/i);
      return m ? m[0].toLowerCase() : null;
    }
    case 'phone': {
      const m = text.match(/\+?[\d\s\-().]{7,}/);
      return m ? m[0].trim() : null;
    }
    case 'linkedin_url': {
      const m = text.match(/(?:https?:\/\/)?(?:www\.)?linkedin\.com\/in\/[\w%-]+\/?/i);
      return m ? m[0] : null;
    }
    default:
      return null;
  }
}

/**
 * Classify a client message against the current question.
 * Returns { intent: 'ANSWER'|'CLARIFICATION'|'UNRELATED', answer: string|null }
 */
async function classifyMessage(questionText, userText, aiFn, previousAnswers = {}) {
  const contextLines = Object.entries(previousAnswers)
    .filter(([, v]) => v && v !== '__skipped__')
    .map(([k, v]) => `- ${k}: ${v}`)
    .join('\n');

  const contextBlock = contextLines
    ? `\nPrevious answers already collected:\n${contextLines}\n`
    : '';

  const prompt = `You are helping a career coaching bot process a WhatsApp message from a job seeker.
${contextBlock}
The bot just asked:
"${questionText}"

The client replied:
"${userText}"

Classify the reply and respond in this exact JSON (no markdown):
{"intent":"ANSWER"|"CLARIFICATION"|"UNRELATED","answer":"<extracted value or null>"}

Rules:
- ANSWER: message answers the question (even partially). Extract the clean value.
  - If the reply is a relative reference like "same", "same as before", "same field", resolve it using the previous answers above to produce a concrete value.
  - If the relative reference is ambiguous and cannot be resolved, return CLARIFICATION instead.
- CLARIFICATION: client is asking what the question means, how to answer it, or used a vague reference that cannot be resolved.
- UNRELATED: completely off-topic.`;

  const result = await aiFn(
    'You are a precise message classifier. Return only valid JSON.',
    [{ role: 'user', content: prompt }],
    'gpt-4.1-mini'
  );

  try {
    const parsed = JSON.parse(result.trim());
    return {
      intent: ['ANSWER', 'CLARIFICATION', 'UNRELATED'].includes(parsed.intent) ? parsed.intent : 'UNRELATED',
      answer: parsed.answer && parsed.answer !== 'null' ? String(parsed.answer).trim() : null,
    };
  } catch {
    return { intent: 'UNRELATED', answer: null };
  }
}

// Check if the client is asking about form progress
function isProgressQuestion(text) {
  return /how many|how far|progress|questions left|questões|quanto falta|combien|avancement|finished|done yet/i.test(text);
}

// ── CV text helper ─────────────────────────────────────────────────────────────

function readCvText(scriptDir, slug) {
  const paths = [
    join(scriptDir, 'mentees', slug, 'cv-personal.txt'),
    join(scriptDir, 'mentees', slug, 'cv-linkedin.txt'),
  ];
  const texts = paths
    .filter(p => existsSync(p))
    .map(p => { try { return readFileSync(p, 'utf8').trim(); } catch { return ''; } })
    .filter(Boolean);
  const combined = texts.join('\n\n---\n\n');
  // Limit to ~4000 chars to keep token usage reasonable
  return combined.length > 4000 ? combined.slice(0, 4000) + '\n[...]' : combined || null;
}

// ── Ask a question ─────────────────────────────────────────────────────────────

/**
 * Build a plain open question (no CV lookup).
 */
async function buildOpenQuestion(question, totalAsked, clientLang, aiFn, TRAINING) {
  const progress = `(${totalAsked}/${QUESTIONS.length})`;
  const prompt = `Rephrase this question warmly and naturally in ${clientLang || 'English'} for a WhatsApp message.
Keep it conversational and friendly. Add the progress indicator "${progress}" at the end.
Question: "${question.en}"
Return ONLY the rephrased question. No preamble. Never start with a greeting (no "Hey!", "Hi!", "Hi [name]!", "Hello!", etc.).`;
  return aiFn(TRAINING, [{ role: 'user', content: prompt }], 'gpt-4.1-mini');
}

/**
 * Build a question, optionally analysing the CV to decide confirmation vs open.
 * Returns { text: string, suggestedValue: string|null }
 */
async function buildQuestion(question, index, totalAsked, clientLang, aiFn, TRAINING, cvText, answers = {}) {
  if (!cvText) {
    return { text: await buildOpenQuestion(question, totalAsked, clientLang, aiFn, TRAINING), suggestedValue: null };
  }

  const progress = `(${totalAsked}/${QUESTIONS.length})`;

  const answeredLines = Object.entries(answers)
    .filter(([, v]) => v && v !== '__skipped__')
    .map(([k, v]) => `- ${k}: ${v}`)
    .join('\n');
  const answeredBlock = answeredLines
    ? `\nAlready collected answers (do NOT ask about these again):\n${answeredLines}\n`
    : '';

  const prompt = `You are helping a career coaching bot ask an onboarding question on WhatsApp.

CV TEXT:
${cvText}
${answeredBlock}
QUESTION: "${question.en}"

INSTRUCTIONS:
1. Look for a clear, reliable answer to this specific question in the CV text.
2. Do NOT suggest a value that duplicates an already-collected answer above.
3. If found: rephrase as a friendly confirmation (e.g. "Your most recent role was X at Y — is that right?"). Return JSON: {"mode":"confirm","suggestedValue":"<value>","text":"<message>"}
4. If not found or uncertain: rephrase as a warm open question. Return JSON: {"mode":"open","suggestedValue":null,"text":"<message>"}

Rules:
- Language: ${clientLang || 'English'}
- Be conversational, no stiff phrasing
- Never start with a greeting (no "Hey!", "Hi!", "Hi [name]!", "Hello!", etc.)
- Append "${progress}" at the end of text
- Return ONLY valid JSON, no markdown`;

  const raw = await aiFn(
    'You are a precise JSON generator. Return only valid JSON.',
    [{ role: 'user', content: prompt }],
    'gpt-4.1-mini'
  );

  try {
    const parsed = JSON.parse(raw.trim());
    if (parsed.text) {
      return {
        text: parsed.text,
        suggestedValue: parsed.mode === 'confirm' && parsed.suggestedValue ? String(parsed.suggestedValue).trim() : null,
      };
    }
  } catch { /* fall through */ }

  return { text: await buildOpenQuestion(question, totalAsked, clientLang, aiFn, TRAINING), suggestedValue: null };
}

/**
 * When the bot asked a confirmation question, classify the client's reply.
 * Returns { intent: 'CONFIRMED'|'CORRECTED'|'DENIED', answer: string|null }
 */
async function classifyConfirmation(questionText, suggestedValue, userText, aiFn) {
  const prompt = `The bot asked a confirmation question: "${questionText}"
The suggested value was: "${suggestedValue}"
The client replied: "${userText}"

Classify:
- CONFIRMED: client agrees (yes, correct, that's right, etc.)
- CORRECTED: client provides a different/updated value — extract it
- DENIED: client says it's wrong but gives no replacement

Return JSON (no markdown): {"intent":"CONFIRMED"|"CORRECTED"|"DENIED","answer":"<value or null>"}`;

  const raw = await aiFn(
    'You are a precise JSON classifier. Return only valid JSON.',
    [{ role: 'user', content: prompt }],
    'gpt-4.1-mini'
  );

  try {
    const parsed = JSON.parse(raw.trim());
    return {
      intent: ['CONFIRMED', 'CORRECTED', 'DENIED'].includes(parsed.intent) ? parsed.intent : 'DENIED',
      answer: parsed.answer && parsed.answer !== 'null' ? String(parsed.answer).trim() : null,
    };
  } catch {
    return { intent: 'DENIED', answer: null };
  }
}

// ── Main form handler ──────────────────────────────────────────────────────────

/**
 * Called for every CLIENT message during the form phase.
 */
export async function handleFormMessage(sock, groupJid, scriptDir, slug, text, clientLang, aiFn, TRAINING) {
  const form = loadForm(scriptDir, slug);
  if (isFormComplete(form)) return 'complete';

  const currentIndex = form.currentIndex || 0;

  // Resolve actual current question (may need to skip pre-filled ones)
  const resolvedIndex = nextUnansweredIndex(currentIndex, form.answers);
  if (resolvedIndex !== currentIndex) {
    form.currentIndex = resolvedIndex;
    saveForm(scriptDir, slug, form);
  }

  if (resolvedIndex >= QUESTIONS.length) {
    form.completedAt = new Date().toISOString();
    saveForm(scriptDir, slug, form);
    return 'complete';
  }

  const currentQ = QUESTIONS[resolvedIndex];
  const progress  = `(${resolvedIndex + 1}/${QUESTIONS.length})`;

  // Progress question?
  if (isProgressQuestion(text)) {
    const answered  = Object.keys(form.answers || {}).filter(k => form.answers[k] !== '__skipped__').length;
    const remaining = QUESTIONS.length - resolvedIndex - 1;
    const progressMsg = await aiFn(
      TRAINING,
      [{ role: 'user', content: `Tell the client they have answered ${answered} questions and have about ${remaining} left. Then re-ask: "${currentQ.en}". End with: ${progress}. Reply in ${clientLang || 'English'}. Be brief.` }],
      'gpt-4.1-mini'
    );
    await sock.sendMessage(groupJid, { text: progressMsg });
    appendGroupMsg(scriptDir, slug, 'assistant', progressMsg);
    return 'ongoing';
  }

  // ── Confirmation flow: bot previously suggested a value from CV ────────────
  const pendingSuggestion = form.pendingSuggestion;
  if (pendingSuggestion && pendingSuggestion.key === currentQ.key) {
    // Try regex first (e.g. user types a corrected phone/email/LinkedIn)
    let answer = extractDirect(currentQ.key, text);

    if (!answer) {
      const { intent, answer: correctedAnswer } = await classifyConfirmation(
        pendingSuggestion.questionText,
        pendingSuggestion.value,
        text,
        aiFn
      );

      if (intent === 'CONFIRMED') {
        answer = pendingSuggestion.value;
      } else if (intent === 'CORRECTED' && correctedAnswer) {
        answer = correctedAnswer;
      } else {
        // Denied or unclear — re-ask openly (without CV suggestion)
        form.pendingSuggestion = null;
        saveForm(scriptDir, slug, form);
        const reask = await buildOpenQuestion(currentQ, resolvedIndex + 1, clientLang, aiFn, TRAINING);
        await sock.sendMessage(groupJid, { text: reask });
        appendGroupMsg(scriptDir, slug, 'assistant', reask);
        return 'ongoing';
      }
    }

    if (answer) {
      if (!form.answers) form.answers = {};
      form.answers[currentQ.key] = answer;
      form.pendingSuggestion = null;
      return await _advanceForm(sock, groupJid, scriptDir, slug, form, resolvedIndex, clientLang, aiFn, TRAINING);
    }
  }

  // ── Standard flow ──────────────────────────────────────────────────────────

  // Try regex extraction first
  let answer = extractDirect(currentQ.key, text);

  // AI classification
  if (!answer) {
    const { intent, answer: aiAnswer } = await classifyMessage(currentQ.en, text, aiFn, form.answers || {});

    if (intent === 'ANSWER') {
      answer = aiAnswer;
    } else if (intent === 'CLARIFICATION') {
      const msg = await aiFn(TRAINING, [{
        role: 'user',
        content: `The client doesn't understand: "${currentQ.en}". Their message: "${text}". Explain simply with a short example, then re-ask in ${clientLang || 'English'}. End with: ${progress}. Return ONLY the message.`,
      }], 'gpt-4.1-mini');
      await sock.sendMessage(groupJid, { text: msg });
      appendGroupMsg(scriptDir, slug, 'assistant', msg);
      return 'ongoing';
    } else {
      const msg = await aiFn(TRAINING, [{
        role: 'user',
        content: `The client sent something off-topic: "${text}". Current question: "${currentQ.en}". Acknowledge briefly and redirect warmly in ${clientLang || 'English'}. End with: ${progress}. Return ONLY the message.`,
      }], 'gpt-4.1-mini');
      await sock.sendMessage(groupJid, { text: msg });
      appendGroupMsg(scriptDir, slug, 'assistant', msg);
      return 'ongoing';
    }
  }

  if (!answer) {
    const reask = await aiFn(TRAINING, [{
      role: 'user',
      content: `Answer to "${currentQ.en}" was unclear: "${text}". Gently re-ask in ${clientLang || 'English'}. End with: ${progress}. Return ONLY the message.`,
    }], 'gpt-4.1-mini');
    await sock.sendMessage(groupJid, { text: reask });
    appendGroupMsg(scriptDir, slug, 'assistant', reask);
    return 'ongoing';
  }

  // Save answer and advance
  if (!form.answers) form.answers = {};
  form.answers[currentQ.key] = answer;
  form.pendingSuggestion = null;
  return await _advanceForm(sock, groupJid, scriptDir, slug, form, resolvedIndex, clientLang, aiFn, TRAINING);
}

/**
 * Save form progress, find next question, ask it (with CV-awareness), return status.
 */
async function _advanceForm(sock, groupJid, scriptDir, slug, form, resolvedIndex, clientLang, aiFn, TRAINING) {
  const nextIndex = nextUnansweredIndex(resolvedIndex + 1, form.answers);

  if (nextIndex >= QUESTIONS.length) {
    form.currentIndex = nextIndex;
    form.completedAt  = new Date().toISOString();
    if (!form.startedAt) form.startedAt = new Date().toISOString();
    saveForm(scriptDir, slug, form);
    return 'complete';
  }

  form.currentIndex = nextIndex;
  if (!form.startedAt) form.startedAt = new Date().toISOString();

  const nextQ   = QUESTIONS[nextIndex];
  const cvText  = readCvText(scriptDir, slug);
  const { text: nextMsg, suggestedValue } = await buildQuestion(nextQ, nextIndex, nextIndex + 1, clientLang, aiFn, TRAINING, cvText, form.answers || {});

  form.pendingSuggestion = suggestedValue
    ? { key: nextQ.key, value: suggestedValue, questionText: nextMsg }
    : null;

  saveForm(scriptDir, slug, form);
  await sock.sendMessage(groupJid, { text: nextMsg });
  appendGroupMsg(scriptDir, slug, 'assistant', nextMsg);
  return 'ongoing';
}

/**
 * Send the first form question (called when form phase starts).
 * Accepts optional prefill data extracted from CV / group.json.
 *
 * @param {object} prefill - { phone, address, date_of_birth, linkedin_url } — any already-known values
 */
export async function startForm(sock, groupJid, scriptDir, slug, clientLang, aiFn, TRAINING, prefill = {}) {
  const form = loadForm(scriptDir, slug);
  if (!form.startedAt) {
    form.startedAt    = new Date().toISOString();
    form.currentIndex = 0;
    form.answers      = {};

    // Pre-fill from career-strategy.json (lead creation data)
    try {
      const stratPath = join(scriptDir, 'mentees', slug, 'career-strategy.json');
      if (existsSync(stratPath)) {
        const strat = JSON.parse(readFileSync(stratPath, 'utf8'));
        if (strat.email)    form.answers.email     = strat.email;
        if (strat.leadName) form.answers.full_name  = strat.leadName;
      }
    } catch {}

    // Pre-fill from CV / group.json passed by caller
    for (const [key, value] of Object.entries(prefill)) {
      if (value && !form.answers[key]) form.answers[key] = value;
    }

    saveForm(scriptDir, slug, form);
  }

  // Find first unanswered question
  const firstIndex = nextUnansweredIndex(0, form.answers);
  if (firstIndex >= QUESTIONS.length) return; // nothing to ask

  form.currentIndex = firstIndex;
  saveForm(scriptDir, slug, form);

  const firstQ  = QUESTIONS[firstIndex];
  const cvText  = readCvText(scriptDir, slug);
  const { text: msg, suggestedValue } = await buildQuestion(firstQ, firstIndex, firstIndex + 1, clientLang, aiFn, TRAINING, cvText, form.answers || {});

  form.pendingSuggestion = suggestedValue
    ? { key: firstQ.key, value: suggestedValue, questionText: msg }
    : null;
  saveForm(scriptDir, slug, form);

  await sock.sendMessage(groupJid, { text: msg });
  appendGroupMsg(scriptDir, slug, 'assistant', msg);
}
