/**
 * groupJobResponse.js — Handles client messages about job opportunities
 *
 * Detects:
 *   - Job interest / decline (natural language matching proposed jobs)
 *   - CV / cover letter feedback or approval (when in review state)
 *   - Status updates (applied, interview, rejected, offer)
 *
 * State tracked in group.json:
 *   cvReview: { jobId, type, url } | null
 */

import { existsSync, readFileSync, writeFileSync } from 'fs';
import { join } from 'path';
import { syncWrite } from './sync.js';
import { generateJobCv, generateCoverLetter, updateDoc, classifyDocMessage, finalizeToPdf, docUrl } from './groupCvBuilder.js';

// ── Job tracking helpers ──────────────────────────────────────────────────────

export function loadJobTracking(scriptDir, slug) {
  const p = join(scriptDir, 'mentees', slug, 'jobtracking.json');
  if (!existsSync(p)) return { slug, jobs: [] };
  try { return JSON.parse(readFileSync(p, 'utf8')); }
  catch { return { slug, jobs: [] }; }
}

export function saveJobTracking(scriptDir, botDir, slug, jt) {
  const p = join(scriptDir, 'mentees', slug, 'jobtracking.json');
  jt.updatedAt = new Date().toISOString();
  writeFileSync(p, JSON.stringify(jt, null, 2));
  syncWrite(botDir, slug, 'jobtracking', jt).catch(e =>
    console.warn('[jobtrack] sync failed:', e.message)
  );
}

function updateJobStatus(jt, jobId, status, extra = {}) {
  const job = (jt.jobs || []).find(j => j.id === jobId);
  if (job) {
    job.status    = status;
    job.updatedAt = new Date().toISOString();
    Object.assign(job, extra);
  }
  return jt;
}

function getProposedJobs(jt) {
  return (jt.jobs || [])
    .filter(j => j.status === 'proposed')
    .slice(-20); // last 20 proposed
}

function getInterestedJobs(jt) {
  return (jt.jobs || []).filter(j => j.status === 'interested');
}

// ── Intent detection ──────────────────────────────────────────────────────────

async function detectIntent(text, proposedJobs, cvReview, aiFn) {
  const jobList = proposedJobs.length
    ? proposedJobs.map((j, i) => `${i + 1}. ${j.title} at ${j.company}${j.location ? ' (' + j.location + ')' : ''} [id:${j.id}]`).join('\n')
    : '';

  const prompt = `You are analysing a WhatsApp message from a job seeker.

${jobList ? `RECENTLY PROPOSED JOBS:\n${jobList}\n\n` : ''}${cvReview ? `CURRENTLY REVIEWING: ${cvReview.type.toUpperCase()} for job id:${cvReview.jobId}\n\n` : ''}MESSAGE: "${text}"

Return a JSON object (no markdown):
{
  "intent": "<intent>",
  "interestedJobIds": [],
  "declinedJobIds": [],
  "statusUpdate": null,
  "statusJobId": null,
  "allDeclined": false
}

Intent options:
- "job_interest"   — client wants to pursue one or more jobs (match by number, company name, or description)
- "job_decline"    — client is not interested in specific or all jobs
- "doc_response"   — client is responding to their CV or cover letter review (ONLY if cvReview is active)
- "status_update"  — client reports applying, getting an interview, rejection, or offer
- "other"          — anything else

For job matching: map company names, keywords, or numbers to job IDs from the list above.
statusUpdate options: "applied" | "interview_scheduled" | "rejected" | "offer" | null`;

  try {
    const raw     = await aiFn('You are a precise intent classifier. Return only JSON.', [{ role: 'user', content: prompt }], 'gpt-4.1-mini');
    const cleaned = raw.replace(/^```(?:json)?\n?/m, '').replace(/\n?```$/m, '').trim();
    return JSON.parse(cleaned);
  } catch {
    return { intent: 'other', interestedJobIds: [], declinedJobIds: [], statusUpdate: null, statusJobId: null, allDeclined: false };
  }
}

// ── CV review handler ─────────────────────────────────────────────────────────

async function handleDocReview(sock, groupJid, scriptDir, botDir, slug, group, text, jt, aiFn, TRAINING, appendFn) {
  const cvReview = group.cvReview;
  const job      = (jt.jobs || []).find(j => j.id === cvReview.jobId);
  const type     = cvReview.type; // 'cv' or 'cover'
  const label    = type === 'cv' ? 'CV' : 'cover letter';
  const lang     = detectLang(text);

  const classification = await classifyDocMessage(text, type, aiFn);

  if (classification === 'approved') {
    // Finalize: generate PDF + send
    const waitMsg = await aiFn(TRAINING, [{
      role: 'user',
      content: `The client just approved their ${label} for ${job?.company || 'the company'}. Acknowledge enthusiastically and say you are generating the PDF. In ${lang}. 1-2 sentences.`
    }], 'gpt-4.1-mini');
    await sock.sendMessage(groupJid, { text: waitMsg });
    appendFn('assistant', waitMsg);

    try {
      const { pdfBuffer, fileName } = await finalizeToPdf(slug, cvReview.jobId, type, group.leadName, scriptDir);

      await sock.sendMessage(groupJid, {
        document: pdfBuffer,
        mimetype: 'application/pdf',
        fileName,
        caption: `✅ ${label.charAt(0).toUpperCase() + label.slice(1)} — ${job?.company || ''}`
      });

      // Update job status
      const newStatus = type === 'cv' ? 'cv_ready' : 'cover_ready';
      jt = updateJobStatus(jt, cvReview.jobId, newStatus);
      if (job) job[type === 'cv' ? 'cvFile' : 'coverLetterFile'] = fileName;
      saveJobTracking(scriptDir, botDir, slug, jt);

      // Clear CV review state
      group.cvReview = null;

      // If CV was approved, offer cover letter
      if (type === 'cv') {
        const coverOffer = await aiFn(TRAINING, [{
          role: 'user',
          content: `CV approved and PDF sent for ${job?.company || 'the company'}. Ask warmly if the client wants a cover letter for this role too. In ${lang}. 1-2 sentences.`
        }], 'gpt-4.1-mini');
        await sock.sendMessage(groupJid, { text: coverOffer });
        appendFn('assistant', coverOffer);
        group.awaitingCoverLetterConfirm = cvReview.jobId;
      } else {
        const doneMsg = await aiFn(TRAINING, [{
          role: 'user',
          content: `Cover letter approved and sent for ${job?.company || 'the company'}. Congratulate the client and wish them luck with the application. Ask if they are ready to submit it. In ${lang}. 2 sentences.`
        }], 'gpt-4.1-mini');
        await sock.sendMessage(groupJid, { text: doneMsg });
        appendFn('assistant', doneMsg);
      }
    } catch (e) {
      console.error('[cvbuilder] finalize failed:', e.message);
      await sock.sendMessage(groupJid, { text: `⚠️ Could not generate PDF: ${e.message}. The HTML version is still available at the link.` });
    }

    return true;
  }

  if (classification === 'feedback') {
    const thinkingMsg = await aiFn(TRAINING, [{
      role: 'user',
      content: `Client gave feedback on their ${label}: "${text}". Acknowledge you are updating it. In ${lang}. 1 sentence only.`
    }], 'gpt-4.1-mini');
    await sock.sendMessage(groupJid, { text: thinkingMsg });
    appendFn('assistant', thinkingMsg);

    try {
      const url = await updateDoc(slug, cvReview.jobId, type, text, aiFn, scriptDir);
      const doneMsg = await aiFn(TRAINING, [{
        role: 'user',
        content: `The ${label} has been updated based on their feedback. Let them know it's ready to review again. In ${lang}. 1-2 sentences. Do NOT include the URL in your reply.`
      }], 'gpt-4.1-mini');
      await sock.sendMessage(groupJid, { text: `${doneMsg}\n\n🔗 ${url}` });
      appendFn('assistant', `${doneMsg}\n\n🔗 ${url}`);
    } catch (e) {
      await sock.sendMessage(groupJid, { text: `⚠️ Could not update the ${label}: ${e.message}` });
    }
    return true;
  }

  // 'other' — respond in context of the active CV review
  const nudge = await aiFn(TRAINING, [{
    role: 'user',
    content: `The client sent a message while reviewing their ${label} for ${job?.company || 'the company'}: "${text}". Respond helpfully in context, then remind them the ${label} is ready for review at ${cvReview.url} and ask if they have any feedback or if it looks good. In ${lang}. Keep it brief.`
  }], 'gpt-4.1-mini');
  await sock.sendMessage(groupJid, { text: nudge });
  appendFn('assistant', nudge);
  return true;
}

// ── Job interest handler ──────────────────────────────────────────────────────

async function handleJobInterest(sock, groupJid, scriptDir, botDir, slug, group, jt, interestedJobIds, text, aiFn, TRAINING, appendFn) {
  if (!interestedJobIds.length) return false;

  const lang = detectLang(text);
  const interestedJobs = (jt.jobs || []).filter(j => interestedJobIds.includes(j.id));
  const firstJob       = interestedJobs[0];

  if (!firstJob) return false;

  // Ask user to confirm the identified job(s) before generating anything
  const jobSummary = interestedJobs.map(j => `*${j.title}* at ${j.company}`).join(', ');
  const confirmMsg = await aiFn(TRAINING, [{
    role: 'user',
    content: `Client expressed interest in a job. You identified: ${jobSummary}. Ask them to confirm this is the right position before you proceed with the CV. Be warm and concise. In ${lang}. 1-2 sentences.`
  }], 'gpt-4.1-mini');
  await sock.sendMessage(groupJid, { text: confirmMsg });
  appendFn('assistant', confirmMsg);

  // Store pending job IDs — wait for confirmation before generating CV
  group.awaitingJobConfirm = interestedJobIds;

  return true;
}

async function handleJobConfirm(sock, groupJid, scriptDir, botDir, slug, group, jt, text, aiFn, TRAINING, appendFn) {
  const interestedJobIds = group.awaitingJobConfirm;
  const lang = detectLang(text);

  const isYes = await aiFn(
    'Classify this as YES or NO.',
    [{ role: 'user', content: `Message: "${text}". Is the person confirming / saying yes? Reply only YES or NO.` }],
    'gpt-4.1-mini'
  );

  group.awaitingJobConfirm = null;

  if (!isYes?.trim().toUpperCase().includes('YES')) {
    // User did not confirm — ask them to clarify which job they meant
    const clarifyMsg = await aiFn(TRAINING, [{
      role: 'user',
      content: `Client did not confirm the job we suggested. Ask them to clarify which position they are interested in (by number or company name). In ${lang}. 1 sentence.`
    }], 'gpt-4.1-mini');
    await sock.sendMessage(groupJid, { text: clarifyMsg });
    appendFn('assistant', clarifyMsg);
    return true;
  }

  // Confirmed — mark as interested and generate CV
  for (const jobId of interestedJobIds) {
    jt = updateJobStatus(jt, jobId, 'interested');
  }
  saveJobTracking(scriptDir, botDir, slug, jt);

  const interestedJobs = (jt.jobs || []).filter(j => interestedJobIds.includes(j.id));
  const firstJob       = interestedJobs[0];
  if (!firstJob) return false;

  const startMsg = await aiFn(TRAINING, [{
    role: 'user',
    content: `Client confirmed interest in ${firstJob.title} at ${firstJob.company}. Say you are now preparing a tailored CV for them. In ${lang}. 1 sentence.`
  }], 'gpt-4.1-mini');
  await sock.sendMessage(groupJid, { text: startMsg });
  appendFn('assistant', startMsg);

  try {
    const cvmaster       = loadJson(join(scriptDir, 'mentees', slug, 'cvmaster.json'));
    const careerStrategy = loadJson(join(scriptDir, 'mentees', slug, 'career-strategy.json'));

    if (!cvmaster?.headline) {
      await sock.sendMessage(groupJid, { text: `⚠️ Career dossier not ready yet — cannot generate CV.` });
      return true;
    }

    const url = await generateJobCv(slug, firstJob.id, firstJob, cvmaster, careerStrategy, aiFn, scriptDir);

    jt = updateJobStatus(jt, firstJob.id, 'cv_review');
    saveJobTracking(scriptDir, botDir, slug, jt);

    group.cvReview = { jobId: firstJob.id, type: 'cv', url };

    const linkMsg = await aiFn(TRAINING, [{
      role: 'user',
      content: `CV for ${firstJob.title} at ${firstJob.company} is ready. Send the link and ask them to review it and give feedback or say it's ok. In ${lang}. 2 sentences max.`
    }], 'gpt-4.1-mini');
    await sock.sendMessage(groupJid, { text: `${linkMsg}\n\n🔗 ${url}` });
    appendFn('assistant', `${linkMsg}\n\n🔗 ${url}`);

    if (interestedJobs.length > 1) {
      const moreMsg = await aiFn(TRAINING, [{
        role: 'user',
        content: `Client is also interested in ${interestedJobs.slice(1).map(j => `${j.title} at ${j.company}`).join(' and ')}. Let them know you'll prepare those CVs after this one is approved. In ${lang}. 1 sentence.`
      }], 'gpt-4.1-mini');
      await sock.sendMessage(groupJid, { text: moreMsg });
      appendFn('assistant', moreMsg);

      group.cvQueue = interestedJobs.slice(1).map(j => j.id);
    }

  } catch (e) {
    console.error('[cvbuilder] generateJobCv failed:', e.message);
    await sock.sendMessage(groupJid, { text: `⚠️ Could not generate CV: ${e.message}` });
  }

  return true;
}

// ── Status update handler ─────────────────────────────────────────────────────

async function handleStatusUpdate(sock, groupJid, scriptDir, botDir, slug, group, jt, statusUpdate, statusJobId, text, aiFn, TRAINING, appendFn) {
  const lang = detectLang(text);

  // Find the job
  let job = statusJobId ? (jt.jobs || []).find(j => j.id === statusJobId) : null;
  if (!job) {
    // Try to find most recent interested/cv_ready job
    job = (jt.jobs || []).filter(j => ['interested', 'cv_ready', 'cover_ready', 'applied'].includes(j.status)).slice(-1)[0];
  }

  if (!job) return false;

  const statusMap = {
    applied:              { status: 'applied',              dateField: 'appliedAt' },
    interview_scheduled:  { status: 'interview_scheduled',  dateField: 'interviewDate' },
    rejected:             { status: 'rejected',             dateField: 'companyResponseDate' },
    offer:                { status: 'offer',                dateField: 'companyResponseDate' },
  };

  const mapping = statusMap[statusUpdate];
  if (!mapping) return false;

  const extra = { [mapping.dateField]: new Date().toISOString() };
  if (statusUpdate === 'rejected') extra.companyResponseType = 'rejected';
  if (statusUpdate === 'offer')    extra.offerReceived = true;

  jt = updateJobStatus(jt, job.id, mapping.status, extra);
  saveJobTracking(scriptDir, botDir, slug, jt);

  const prompts = {
    applied:             `Client confirmed they applied to ${job.title} at ${job.company}. Congratulate them and encourage them to keep going. In ${lang}. 2 sentences.`,
    interview_scheduled: `Client has an interview scheduled for ${job.title} at ${job.company}. Express excitement and say you'll help them prepare. In ${lang}. 2 sentences.`,
    rejected:            `Client was rejected from ${job.title} at ${job.company}. Be empathetic, encouraging, remind them this is part of the process. In ${lang}. 2-3 sentences.`,
    offer:               `Client received an offer from ${job.company} for ${job.title}! Express genuine excitement and ask for details. In ${lang}. 2 sentences.`,
  };

  const reply = await aiFn(TRAINING, [{ role: 'user', content: prompts[statusUpdate] }], 'gpt-4.1-mini');
  await sock.sendMessage(groupJid, { text: reply });
  appendFn('assistant', reply);
  return true;
}

// ── Cover letter confirmation handler ─────────────────────────────────────────

async function handleCoverLetterConfirm(sock, groupJid, scriptDir, botDir, slug, group, jt, text, aiFn, TRAINING, appendFn) {
  const jobId = group.awaitingCoverLetterConfirm;
  const lang  = detectLang(text);

  const isYes = await aiFn(
    'Classify this as YES or NO.',
    [{ role: 'user', content: `Message: "${text}". Does the person want to proceed with a cover letter? Reply only YES or NO.` }],
    'gpt-4.1-mini'
  );

  group.awaitingCoverLetterConfirm = null;

  if (isYes?.trim().toUpperCase().includes('YES')) {
    const job = (jt.jobs || []).find(j => j.id === jobId);
    if (!job) return false;

    const thinkMsg = await aiFn(TRAINING, [{
      role: 'user',
      content: `Client wants a cover letter for ${job.title} at ${job.company}. Say you are preparing it. In ${lang}. 1 sentence.`
    }], 'gpt-4.1-mini');
    await sock.sendMessage(groupJid, { text: thinkMsg });
    appendFn('assistant', thinkMsg);

    try {
      const cvmaster       = loadJson(join(scriptDir, 'mentees', slug, 'cvmaster.json'));
      const careerStrategy = loadJson(join(scriptDir, 'mentees', slug, 'career-strategy.json'));
      const url            = await generateCoverLetter(slug, jobId, job, cvmaster, careerStrategy, aiFn, scriptDir);

      jt = updateJobStatus(jt, jobId, 'cover_review');
      saveJobTracking(scriptDir, botDir, slug, jt);
      group.cvReview = { jobId, type: 'cover', url };

      const linkMsg = await aiFn(TRAINING, [{
        role: 'user',
        content: `Cover letter for ${job.company} is ready. Send the link, ask them to review. In ${lang}. 1-2 sentences.`
      }], 'gpt-4.1-mini');
      await sock.sendMessage(groupJid, { text: `${linkMsg}\n\n🔗 ${url}` });
      appendFn('assistant', `${linkMsg}\n\n🔗 ${url}`);
    } catch (e) {
      await sock.sendMessage(groupJid, { text: `⚠️ Cover letter error: ${e.message}` });
    }
  } else {
    const skipMsg = await aiFn(TRAINING, [{
      role: 'user',
      content: `Client skipped the cover letter. That's fine, acknowledge it and wish them luck. In ${lang}. 1 sentence.`
    }], 'gpt-4.1-mini');
    await sock.sendMessage(groupJid, { text: skipMsg });
    appendFn('assistant', skipMsg);
  }
  return true;
}

// ── Main entry point ──────────────────────────────────────────────────────────

/**
 * Handle a client message in the active phase related to jobs.
 * Returns true if the message was handled, false to fall through to @mention handler.
 */
export async function handleJobMessage(sock, groupJid, scriptDir, botDir, slug, group, text, senderNum, numbers, aiFn, TRAINING, appendFn, saveGroupFn) {
  const isCoach = numbers.some(n => n.number === senderNum);

  const jt = loadJobTracking(scriptDir, slug);

  // ── 1. Cover letter confirmation pending ────────────────────────────────────
  if (!isCoach && group.awaitingCoverLetterConfirm) {
    const handled = await handleCoverLetterConfirm(sock, groupJid, scriptDir, botDir, slug, group, jt, text, aiFn, TRAINING, appendFn);
    saveGroupFn(group);
    return handled;
  }

  // ── 1b. Job position confirmation pending ───────────────────────────────────
  if (!isCoach && group.awaitingJobConfirm) {
    const handled = await handleJobConfirm(sock, groupJid, scriptDir, botDir, slug, group, jt, text, aiFn, TRAINING, appendFn);
    saveGroupFn(group);
    return handled;
  }

  // ── 2. CV / cover letter review ─────────────────────────────────────────────
  if (group.cvReview) {
    const handled = await handleDocReview(sock, groupJid, scriptDir, botDir, slug, group, text, jt, aiFn, TRAINING, appendFn);
    saveGroupFn(group);
    return true; // always handle when cvReview is active — don't fall through
  }

  // Coaches don't trigger job selection or status updates
  if (isCoach) return false;

  // ── 3. Detect job intent ─────────────────────────────────────────────────────
  const proposedJobs = getProposedJobs(jt);
  const hasActivity  = proposedJobs.length > 0 || getInterestedJobs(jt).length > 0;

  if (!hasActivity) return false; // no jobs context yet

  const intent = await detectIntent(text, proposedJobs, group.cvReview, aiFn);
  console.log(`[job] intent: ${intent.intent} | interested: [${intent.interestedJobIds?.join(',')}]`);

  if (intent.intent === 'job_interest' && intent.interestedJobIds?.length) {
    const handled = await handleJobInterest(sock, groupJid, scriptDir, botDir, slug, group, jt, intent.interestedJobIds, text, aiFn, TRAINING, appendFn);
    saveGroupFn(group);
    return handled;
  }

  if (intent.intent === 'job_decline') {
    const jobIds = intent.allDeclined
      ? proposedJobs.map(j => j.id)
      : (intent.declinedJobIds || []);

    const declinedJobs = (jt.jobs || []).filter(j => jobIds.includes(j.id));

    if (jobIds.length) {
      for (const id of jobIds) updateJobStatus(jt, id, 'declined');
      saveJobTracking(scriptDir, botDir, slug, jt);
    }

    const lang = detectLang(text);
    const declinedSummary = declinedJobs.map(j => `${j.title} at ${j.company}`).join(', ');
    const promptContent = intent.allDeclined
      ? `Client declined all proposed job opportunities today. Client message: "${text}". Acknowledge warmly — new ones will come tomorrow. If the client gave a reason (e.g. "too specialist", "too junior", "wrong location"), emit UPDATEDATA with the relevant profile field update (e.g. exclusions, seniority, location) so future searches improve. Always use the term "job opportunity" not "job offer". In ${lang}. 2-3 sentences max.`
      : `Client declined ${declinedJobs.length > 0 ? declinedSummary : `${jobIds.length} job opportunit${jobIds.length === 1 ? 'y' : 'ies'}`}. Client message: "${text}". Acknowledge and say you'll keep this in mind for the next batch. If the client gave a reason (e.g. "too specialist", "too junior", "wrong industry"), emit UPDATEDATA with the relevant profile field update so future searches improve. Always use the term "job opportunity" not "job offer". In ${lang}. 1-2 sentences max.`;

    let reply = await aiFn(TRAINING, [{ role: 'user', content: promptContent }], 'gpt-4.1-mini');

    // Apply any UPDATEDATA emitted by the AI
    const mUpdate = reply.match(/UPDATEDATA\((\{[\s\S]*?\})\)/i);
    if (mUpdate) {
      try {
        const payload   = JSON.parse(mUpdate[1]);
        const stratPath = join(scriptDir, 'mentees', slug, 'career-strategy.json');
        const existing  = existsSync(stratPath) ? JSON.parse(readFileSync(stratPath, 'utf8')) : {};
        const merged    = { ...existing, ...payload };
        writeFileSync(stratPath, JSON.stringify(merged, null, 2));
        syncWrite(botDir, slug, 'career-strategy', merged).catch(() => {});
        console.log(`[job] profile updated from decline feedback:`, payload);
      } catch (e) {
        console.error('[job] UPDATEDATA in decline failed:', e.message);
      }
      reply = reply.replace(/UPDATEDATA\([\s\S]*?\)\s*/i, '').trim();
    }

    await sock.sendMessage(groupJid, { text: reply });
    appendFn('assistant', reply);
    return true;
  }

  if (intent.intent === 'status_update' && intent.statusUpdate) {
    return handleStatusUpdate(sock, groupJid, scriptDir, botDir, slug, group, jt, intent.statusUpdate, intent.statusJobId, text, aiFn, TRAINING, appendFn);
  }

  return false; // not a job-related message
}

// ── Helpers ───────────────────────────────────────────────────────────────────

function loadJson(p) {
  if (!existsSync(p)) return {};
  try { return JSON.parse(readFileSync(p, 'utf8')); } catch { return {}; }
}

function detectLang(text) {
  if (!text) return 'English';
  const t = text.toLowerCase();
  if (/\b(bonjour|merci|je|vous|salut)\b/.test(t)) return 'French';
  if (/\b(olá|obrigad|você|tudo|bom|boa)\b/.test(t)) return 'Portuguese';
  if (/\b(hola|gracias|cómo|estás|soy)\b/.test(t)) return 'Spanish';
  return 'English';
}
