import { simpleGit } from "simple-git";
import OpenAI from "openai";

const OLLAMA_BASE_URL = process.env.OLLAMA_BASE_URL || "http://localhost:11434/v1";
const OLLAMA_API_URL = "http://localhost:11434/api";

export async function detectOllamaModel(): Promise<string | null> {
  // Priority: env var > auto-detect > null
  if (process.env.OLLAMA_MODEL) return process.env.OLLAMA_MODEL;
  try {
    const res = await fetch(`${OLLAMA_API_URL}/tags`, { signal: AbortSignal.timeout(3000) });
    if (!res.ok) return null;
    const data = await res.json();
    const models: string[] = (data.models || []).map((m: any) => m.name);
    if (models.length === 0) return null;
    // Prefer smaller/faster models first
    const preferred = ["gemma4", "gemma3", "gemma", "llama3.2", "llama3", "phi", "qwen", "mistral"];
    for (const p of preferred) {
      const match = models.find((m) => m.includes(p));
      if (match) return match;
    }
    return models[0];
  } catch {
    return null;
  }
}

export interface GitCommit {
  hash: string;
  shortHash: string;
  author: string;
  email: string;
  date: Date;
  message: string;
  files: number;
  insertions: number;
  deletions: number;
  filesList: { path: string; additions: number; deletions: number }[];
}

export interface RepoStats {
  repoPath: string;
  repoName: string;
  totalCommits: number;
  totalLinesAdded: number;
  totalLinesDeleted: number;
  totalFilesChanged: number;
  activeDays: number;
  contributors: AuthorStats[];
  topContributor: AuthorStats;
  mostActivePeriod: { type: string; count: number };
  commitTypes: CommitTypeStats[];
  timeSeries: TimeSeriesData;
  heatmap: HeatmapDay[];
  fileChanges: FileChangeStats[];
  summary: string;
  recentCommits: GitCommit[];
}

export interface AuthorStats {
  name: string;
  email: string;
  commits: number;
  linesAdded: number;
  linesDeleted: number;
  daysActive: number;
}

export interface CommitTypeStats {
  type: string;
  count: number;
  percentage: number;
}

export interface TimeSeriesData {
  daily: TimePoint[];
  weekly: TimePoint[];
  monthly: TimePoint[];
}

export interface TimePoint {
  date: string;
  dateLabel: string;
  count: number;
  linesAdded: number;
  linesDeleted: number;
}

export interface HeatmapDay {
  date: string;
  day: number;
  count: number;
  level: number;
}

export interface FileChangeStats {
  path: string;
  additions: number;
  deletions: number;
  totalChanges: number;
  commits: number;
}

export interface ComparisonData {
  repos: RepoStats[];
  labels: string[];
  commitComparison: { repo: string; commits: number; linesAdded: number; linesDeleted: number }[];
  contributorComparison: { name: string; repos: string[] }[];
}

const KNOWN_COMMIT_TYPES = ["feat", "fix", "refactor", "docs", "style", "chore", "perf", "test", "ci", "build", "revert"] as const;
type KnownCommitType = (typeof KNOWN_COMMIT_TYPES)[number];

const COMMIT_TYPE_LABELS: Record<KnownCommitType, string> = {
  feat: "Nouveau",
  fix: "Correction",
  refactor: "Refactorisation",
  docs: "Documentation",
  style: "Style",
  chore: "Tâche",
  perf: "Performance",
  test: "Test",
  ci: "CI/CD",
  build: "Build",
  revert: "Annulation",
};

const DAYS_FR = ["Dim", "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam"];
const MONTHS_FR = ["Jan", "Fév", "Mar", "Avr", "Mai", "Jun", "Jul", "Aoû", "Sep", "Oct", "Nov", "Déc"];

function analyzeCommitType(msg: string): KnownCommitType {
  const lower = msg.toLowerCase().trim();
  for (const type of KNOWN_COMMIT_TYPES) {
    if (lower.startsWith(`${type}:`) || lower.startsWith(`${type}(`) || lower.startsWith(`[${type}]`)) {
      return type;
    }
  }
  for (const type of KNOWN_COMMIT_TYPES) {
    if (lower.includes(`${type}:`) || lower.includes(`${type} `)) {
      return type;
    }
  }
  return "chore";
}

export function getHeatmapLevel(count: number): number {
  if (count === 0) return 0;
  if (count <= 3) return 1;
  if (count <= 6) return 2;
  if (count <= 10) return 3;
  if (count <= 20) return 4;
  return 5;
}

export function formatHeatmapColor(level: number): string {
  const colors = ["#ebedf0", "#c6e48e", "#7bc96f", "#239a3b", "#196127", "#006031"];
  return colors[level] || colors[0];
}

export function getContributionsColor(level: number): string {
  const colors = ["hsl(var(--muted))", "#9BE9A8", "#40C463", "#30A14E", "#216E3A", "#1E6C25"];
  return colors[level] || colors[0];
}

export function formatDateFr(date: Date): string {
  const d = date.getDate();
  const m = MONTHS_FR[date.getMonth()];
  const y = date.getFullYear();
  return `${d} ${m} ${y}`;
}

export function formatShortDateFr(date: Date): string {
  const d = date.getDate();
  const m = MONTHS_FR[date.getMonth()];
  return `${d} ${m}`;
}

export function formatNumber(n: number): string {
  if (n >= 1000000) return `${(n / 1000000).toFixed(1)}M`;
  if (n >= 1000) return `${(n / 1000).toFixed(1)}K`;
  return n.toString();
}

export function getDaysAgo(date: Date): number {
  const now = new Date();
  const diff = now.getTime() - date.getTime();
  return Math.floor(diff / (1000 * 60 * 60 * 24));
}

export function getRelevantDates(
  commits: GitCommit[],
  days: number = 365,
  startDate?: Date
) {
  const start = startDate
    ? new Date(startDate)
    : new Date();
  start.setDate(start.getDate() - days);
  start.setHours(0, 0, 0, 0);

  return commits.filter((c) => c.date >= start);
}

export async function analyzeGitRepo(
  repoPath: string,
  branch: string = "main",
  days: number = 365,
  options: { apiKey?: string; maxCommits?: number; skipAI?: boolean } = {}
): Promise<RepoStats> {
  const git = simpleGit(repoPath);

  await git.checkIsRepo();

  const repo = await simpleGit(repoPath).revparse(["--show-toplevel"]);
  const repoName = Array.isArray(repo) ? repo[repo.length - 1] : repo;

  // Use git raw with --numstat to get per-file additions/deletions
  const maxCount = options.maxCommits ?? 5000;
  const gitLogRaw = await git.raw([
    "log",
    "--numstat",
    "-n", String(maxCount),
    "--format=%H|||%h|||%an|||%ae|||%aI|||%s",
  ]);

  // Parse: each commit block starts with hash|||... followed by numstat file lines
  const relevantCommits: GitCommit[] = [];
  const blocks = gitLogRaw.trim().split(/\n(?=[0-9a-f]{40}\|\|\|)/);

  for (const block of blocks) {
    const lines = block.trim().split("\n");
    const header = lines[0];
    const parts = header.split("|||");
    if (parts.length < 6) continue;

    const hash = parts[0];
    const shortHash = parts[1];
    const author = parts[2];
    const email = parts[3];
    const date = new Date(parts[4]);
    const message = parts[5] || "";

    // Parse numstat lines: "additions\tsuppressions\tpath"
    let totalAdditions = 0;
    let totalDeletions = 0;
    const filesList: { path: string; additions: number; deletions: number }[] = [];

    for (let i = 1; i < lines.length; i++) {
      const line = lines[i].trim();
      if (!line) continue;
      // numstat format: "additions\tdeletions\tpath" (additions/deletions can be "-" for binary)
      const m = line.match(/^(\d+|-)\t(\d+|-)\t(.+)$/);
      if (m) {
        const adds = m[1] === "-" ? 0 : parseInt(m[1]);
        const dels = m[2] === "-" ? 0 : parseInt(m[2]);
        const path = m[3];
        totalAdditions += adds;
        totalDeletions += dels;
        filesList.push({ path, additions: adds, deletions: dels });
      }
    }

    const filesChanged = filesList.length;

    // Apply date filter if needed
    if (days < 365) {
      const cutoff = new Date();
      cutoff.setDate(cutoff.getDate() - days);
      if (date < cutoff) continue;
    }

    relevantCommits.push({
      hash,
      shortHash,
      author,
      email,
      date,
      message,
      files: filesChanged,
      insertions: totalAdditions,
      deletions: totalDeletions,
      filesList,
    });
  }

  const totalCommits = relevantCommits.length;

  const totalLinesAdded = relevantCommits.reduce((s, c) => s + c.insertions, 0);
  const totalLinesDeleted = relevantCommits.reduce((s, c) => s + c.deletions, 0);
  const totalFilesChanged = relevantCommits.reduce((s, c) => s + c.files, 0);

  const activeDaysSet = new Set(relevantCommits.map((c) => c.date.toDateString()));
  const activeDays = activeDaysSet.size;

  const authorMap = new Map<string, AuthorStats>();
  const authorDays = new Map<string, Set<string>>();
  for (const c of relevantCommits) {
    const key = `${c.author}<${c.email}>`;
    if (!authorMap.has(key)) {
      authorMap.set(key, { name: c.author, email: c.email, commits: 0, linesAdded: 0, linesDeleted: 0, daysActive: 0 });
    }
    const authorStat = authorMap.get(key)!;
    authorStat.commits += 1;
    authorStat.linesAdded += c.insertions;
    authorStat.linesDeleted += c.deletions;

    if (!authorDays.has(key)) authorDays.set(key, new Set());
    authorDays.get(key)!.add(c.date.toDateString());
  }

  for (const [key, days] of authorDays) {
    authorMap.get(key)!.daysActive = days.size;
  }

  const contributors = Array.from(authorMap.values())
    .sort((a, b) => b.commits - a.commits);

  const topContributor = contributors[0] || { name: "Aucun", email: "", commits: 0, linesAdded: 0, linesDeleted: 0, daysActive: 0 };

  const today = new Date();
  today.setHours(23, 59, 59, 999);
  const dayStart = new Date(today);
  dayStart.setHours(0, 0, 0, 0);
  const dayEnd = new Date(today);
  dayEnd.setHours(23, 59, 59, 999);

  const weekStart = new Date(today);
  weekStart.setDate(weekStart.getDate() - weekStart.getDay());
  weekStart.setHours(0, 0, 0, 0);
  const weekEnd = new Date(weekStart);
  weekEnd.setDate(weekEnd.getDate() + 6);
  weekEnd.setHours(23, 59, 59, 999);

  const monthStart = new Date(today.getFullYear(), today.getMonth(), 1);
  monthStart.setHours(0, 0, 0, 0);
  const monthEnd = new Date(today.getFullYear(), today.getMonth() + 1, 0, 23, 59, 59, 999);

  const commitByDay: Record<string, GitCommit[]> = {};
  const commitByWeek: Record<string, GitCommit[]> = {};
  const commitByMonth: Record<string, GitCommit[]> = {};

  for (const c of relevantCommits) {
    const ds = c.date.toISOString().split("T")[0];
    if (!commitByDay[ds]) commitByDay[ds] = [];
    commitByDay[ds].push(c);

    const ws = weekStart.toISOString();
    if (c.date >= weekStart && c.date <= weekEnd) {
      const wkIdx = Math.floor((c.date.getTime() - weekStart.getTime()) / (7 * 24 * 60 * 60 * 1000));
      const wkKey = `${weekStart.getFullYear()}-S${String(wkIdx + 1).padStart(2, "0")}`;
      if (!commitByWeek[wkKey]) commitByWeek[wkKey] = [];
      commitByWeek[wkKey].push(c);
    }

    const ms = `${c.date.getFullYear()}-${String(c.date.getMonth() + 1).padStart(2, "0")}`;
    if (!commitByMonth[ms]) commitByMonth[ms] = [];
    commitByMonth[ms].push(c);
  }

  const todayDayCount = commitByDay[dayStart.toISOString().split("T")[0]]?.length ?? 0;
  const weekDayCount = commitByWeek[`${weekStart.getFullYear()}-S${String(Math.floor((today.getTime() - weekStart.getTime()) / (7 * 24 * 60 * 60 * 1000) + 1)).padStart(2, "0")}`]?.length ?? 0;
  const monthDayCount = commitByMonth[`${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, "0")}`]?.length ?? 0;

  let mostActivePeriod = { type: "Aujourd'hui", count: todayDayCount };
  if (weekDayCount > mostActivePeriod.count) mostActivePeriod = { type: "Cette semaine", count: weekDayCount };
  if (monthDayCount > mostActivePeriod.count) mostActivePeriod = { type: "Ce mois", count: monthDayCount };

  const daily: TimePoint[] = [];
  const now = Date.now();
  for (let i = 0; i < days; i++) {
    const date = new Date(now - i * 24 * 60 * 60 * 1000);
    const key = date.toISOString().split("T")[0];
    const count = commitByDay[key]?.length ?? 0;
    const ins = commitByDay[key]?.reduce((s, c) => s + c.insertions, 0) ?? 0;
    const dels = commitByDay[key]?.reduce((s, c) => s + c.deletions, 0) ?? 0;
    daily.push({
      date: key,
      dateLabel: formatShortDateFr(date),
      count,
      linesAdded: ins,
      linesDeleted: dels,
    });
  }

  for (let i = 0; i < 20; i++) {
    const weekStartCalc = new Date(now - i * 7 * 24 * 60 * 60 * 1000);
    weekStartCalc.setHours(0, 0, 0, 0);
    const weekEndCalc = new Date(weekStartCalc);
    weekEndCalc.setDate(weekEndCalc.getDate() + 6);
    weekEndCalc.setHours(23, 59, 59, 999);
    const weekCommits = relevantCommits.filter((c) => c.date >= weekStartCalc && c.date <= weekEndCalc);
    if (weekCommits.length > 0) {
      const wkIdx = i + 1;
      const wkKey = `${weekStartCalc.getFullYear()}-S${String(Math.ceil((weekStartCalc.getTime() - new Date(weekStartCalc.getFullYear(), 0, 1).getTime()) / (7 * 24 * 60 * 60 * 1000) + 1)).padStart(2, "0")}`;
      daily.push({
        date: weekStartCalc.toISOString().split("T")[0],
        dateLabel: `S${wkIdx} (${formatShortDateFr(weekStartCalc)})`,
        count: weekCommits.length,
        linesAdded: weekCommits.reduce((s, c) => s + c.insertions, 0),
        linesDeleted: weekCommits.reduce((s, c) => s + c.deletions, 0),
      });
    }
  }

  const weekly = Object.entries(commitByWeek)
    .sort(([a], [b]) => a.localeCompare(b))
    .map(([label, commits]) => ({
      date: label,
      dateLabel: label,
      count: commits.length,
      linesAdded: commits.reduce((s, c) => s + c.insertions, 0),
      linesDeleted: commits.reduce((s, c) => s + c.deletions, 0),
    }));

  const monthly = Object.entries(commitByMonth)
    .sort(([a], [b]) => a.localeCompare(b))
    .map(([label, commits]) => {
      const [year, monthStr] = label.split("-");
      const monthNum = parseInt(monthStr) - 1;
      return {
        date: label,
        dateLabel: `${MONTHS_FR[monthNum]} ${year}`,
        count: commits.length,
        linesAdded: commits.reduce((s, c) => s + c.insertions, 0),
        linesDeleted: commits.reduce((s, c) => s + c.deletions, 0),
      };
    });

  const commitTypeMap = new Map<KnownCommitType, number>();
  for (const type of KNOWN_COMMIT_TYPES) commitTypeMap.set(type, 0);
  for (const c of relevantCommits) {
    const t = analyzeCommitType(c.message);
    commitTypeMap.set(t, (commitTypeMap.get(t) || 0) + 1);
  }

  const commitTypes: CommitTypeStats[] = [];
  for (const [type, count] of commitTypeMap.entries()) {
    commitTypes.push({
      type,
      count,
      percentage: totalCommits > 0 ? Math.round((count / totalCommits) * 100) : 0,
    });
  }
  commitTypes.sort((a, b) => b.count - a.count);

  const heatmap: HeatmapDay[] = [];
  for (let i = 0; i < days; i++) {
    const date = new Date(now - i * 24 * 60 * 60 * 1000);
    const ds = date.toISOString().split("T")[0];
    const dayCommits = commitByDay[ds] || [];
    const count = dayCommits.length;
    const level = getHeatmapLevel(count);

    heatmap.push({
      date: ds,
      day: date.getDay(),
      count,
      level,
    });
  }

  const fileMap = new Map<string, { additions: number; deletions: number; commits: Set<string> }>();
  for (const c of relevantCommits) {
    for (const f of c.filesList) {
      const key = f.path;
      if (!fileMap.has(key)) fileMap.set(key, { additions: 0, deletions: 0, commits: new Set() });
      const entry = fileMap.get(key)!;
      entry.additions += f.additions;
      entry.deletions += f.deletions;
      entry.commits.add(c.hash);
    }
  }

  const fileChanges: FileChangeStats[] = Array.from(fileMap.entries())
    .map(([path, data]) => ({
      path,
      additions: data.additions,
      deletions: data.deletions,
      totalChanges: data.additions + data.deletions,
      commits: data.commits.size,
    }))
    .sort((a, b) => b.totalChanges - a.totalChanges)
    .slice(0, 50);

  let summary = "";

  const daysRange = days;
  const avgCommitsPerDay = totalCommits / Math.max(daysRange, 1);
  const avgFilesPerCommit = totalFilesChanged / Math.max(totalCommits, 1);

  summary += `Le projet "${repoName}" présente ${totalCommits} commits sur les derniers ${daysRange} jours.\n\n`;
  summary += `- ${contributors.length} contributeur(s) actif(s)\n`;
  summary += `- ${totalLinesAdded} lignes ajoutées (+), ${totalLinesDeleted} lignes supprimées (-)\n`;
  summary += `- ${totalFilesChanged} fichiers modifiés\n`;
  summary += `- ${activeDays} jours actifs\n`;
  summary += `- Moyenne : ${avgCommitsPerDay.toFixed(1)} commits/jour\n`;
  summary += `- ${contributors.length > 0 ? topContributor.name : "N/A"} est le contributeur principal\n\n`;

  const topType = commitTypes[0];
  if (topType) {
    summary += `Type de commit le plus fréquent : "${COMMIT_TYPE_LABELS[topType.type as KnownCommitType] || topType.type}" (${topType.count}, ${topType.percentage}%)\n`;
  }

  const maxActiveWeeks: Array<{ week: number; count: number }> = [];
  for (let w = 0; w < 52; w++) {
    const wkStart = new Date(now - w * 7 * 24 * 60 * 60 * 1000);
    wkStart.setHours(0, 0, 0, 0);
    const wkEnd = new Date(wkStart);
    wkEnd.setDate(wkEnd.getDate() + 6);
    wkEnd.setHours(23, 59, 59, 999);
    const count = relevantCommits.filter((c) => c.date >= wkStart && c.date <= wkEnd).length;
    if (count > 0) maxActiveWeeks.push({ week: w + 1, count });
  }
  const topWeek = maxActiveWeeks.sort((a, b) => b.count - a.count)[0];
  if (topWeek) {
    summary += `Semaine la plus active : S${String(topWeek.week).padStart(2, "0")} (${topWeek.count} commits)\n`;
  }

  if (avgFilesPerCommit > 3) {
    summary += `Les commits sont larges en moyenne (${avgFilesPerCommit.toFixed(1)} fichiers/commit). Il pourrait être utile de découper les modifications.\n`;
  }

  if (contributors.length > 1) {
    const topContribs = contributors.slice(0, 3).map((c) => c.name).join(", ");
    summary += `Top contributeurs : ${topContribs}\n`;
  }

  if (totalCommits === 0) {
    summary += "Aucun commit trouvé dans la période sélectionnée.";
  }

  return {
    repoPath,
    repoName: repoName.replace(/\/$/, ""),
    totalCommits,
    totalLinesAdded,
    totalLinesDeleted,
    totalFilesChanged,
    activeDays,
    contributors,
    topContributor,
    mostActivePeriod,
    commitTypes,
    timeSeries: { daily: daily.reverse(), weekly, monthly },
    heatmap,
    fileChanges,
    summary,
    recentCommits: relevantCommits.slice(0, 200),
  };
}

export function compareRepos(
  repos: Array<{ path: string; name: string }>,
  days = 365,
  options = {}
): Promise<ComparisonData> {
  return Promise.all(
    repos.map((repo) =>
      analyzeGitRepo(repo.path, undefined, days, options).catch(() => null)
    )
  ).then((results): ComparisonData => {
    const validRepos = results.filter((r) => r !== null) as RepoStats[];
    return {
      repos: validRepos,
      labels: repos.map((r) => r.name),
      commitComparison: validRepos.map((r) => ({
        repo: r.repoName,
        commits: r.totalCommits,
        linesAdded: r.totalLinesAdded,
        linesDeleted: r.totalLinesDeleted,
      })),
      contributorComparison: [],
    };
  });
}

export function exportToCSV(stats: RepoStats, filename: string = "git-stats"): string {
  const lines: string[] = [];
  const sep = ";";

  const pushHeader = (headers: string[]) => lines.push(headers.join(sep));
  const pushRow = (row: string[]) => lines.push(row.join(sep));

  lines.push(`Statistiques Git${sep}${stats.repoName.toUpperCase()}`);
  lines.push(`Date${sep}${new Date().toLocaleDateString("fr-FR")}`);
  lines.push(``);

  lines.push("INDICATEUR VALEUR");
  lines.push(`Total commits${sep}${stats.totalCommits}`);
  lines.push(`Lignes ajoutées${sep}${stats.totalLinesAdded}`);
  lines.push(`Lignes supprimées${sep}${stats.totalLinesDeleted}`);
  lines.push(`Fichiers modifiés${sep}${stats.totalFilesChanged}`);
  lines.push(`Jours actifs${sep}${stats.activeDays}`);
  lines.push(``);

  lines.push("CONTRIBUTEURS");
  pushHeader(["Nom", "Email", "Commits", "Lignes ajoutées", "Lignes supprimées", "Jours actifs"]);
  for (const c of stats.contributors) {
    pushRow([c.name, c.email, String(c.commits), String(c.linesAdded), String(c.linesDeleted), String(c.daysActive)]);
  }
  lines.push(``);

  lines.push("TYPES DE COMMITS");
  pushHeader(["Type", "Nom français", "Nombre", "Pourcentage"]);
  for (const t of stats.commitTypes) {
    pushRow([t.type, COMMIT_TYPE_LABELS[t.type as KnownCommitType] || t.type, String(t.count), `${t.percentage}%`]);
  }
  lines.push(``);

  lines.push("MODIFICATIONS DE FICHIERS");
  pushHeader(["Fichier", "Ajouts", "Suppressions", "Total", "Commits"]);
  for (const f of stats.fileChanges.slice(0, 30)) {
    pushRow([f.path, String(f.additions), String(f.deletions), String(f.totalChanges), String(f.commits)]);
  }

  const content = lines.join("\n");
  const bom = "\uFEFF";
  return bom + content;
}

// ==================== AI Summary (async, separate from analysis) ====================

export async function generateAISummary(stats: RepoStats, model?: string): Promise<string> {
  const selectedModel = model || (await detectOllamaModel());
  if (!selectedModel) return "Aucun modèle Ollama disponible. Lancez `ollama pull gemma4`.";

  try {
    // Build context
    const commitSamples = (stats.recentCommits || []).slice(0, 15)
      .map((c) => `[${c.author}] ${c.message}`)
      .join("\n");

    const systemPrompt = `Tu es un expert en analyse de projets Git. Réponds TOUJOURS en français, de façon concise. Format demandé :
📊 Activité : [1 phrase]
👥 Équipe : [1 phrase]
🔧 Code : [1 phrase]  
💡 Conseil : [1 phrase]`;

    const userPrompt = `Projet : ${stats.repoName}
Période : ${stats.activeDays}j actifs, ${stats.totalCommits} commits
+${stats.totalLinesAdded} / −${stats.totalLinesDeleted} lignes
${stats.contributors.length} contributeurs : ${stats.contributors.slice(0, 5).map(c => c.name).join(", ")}
Types : ${stats.commitTypes.filter(t => t.count > 0).map(t => `${t.type} ${t.percentage}%`).join(", ")}
Fichiers modifiés : ${stats.totalFilesChanged}

Commits récents :
${commitSamples}`;

    // Use Ollama native API (more reliable than OpenAI compat for thinking models)
    const ollamaUrl = OLLAMA_BASE_URL.replace(/\/v1$/, "");
    const res = await fetch(`${ollamaUrl}/api/chat`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        model: selectedModel,
        messages: [
          { role: "system", content: systemPrompt },
          { role: "user", content: userPrompt },
        ],
        stream: false,
        options: { temperature: 0.7, num_predict: 400 },
      }),
    });

    if (!res.ok) {
      const err = await res.text();
      throw new Error(`HTTP ${res.status}: ${err.slice(0, 200)}`);
    }

    const data = await res.json();
    const content = data.message?.content?.trim();

    if (!content || content.length < 10) {
      // Maybe the model returned thinking output instead of content
      return `Erreur : réponse vide du modèle ${selectedModel}. Le modèle peut nécessiter un format différent. Essayez \`ollama pull llama3.2\`.`;
    }

    return content;
  } catch (error: any) {
    return `Erreur Ollama (${selectedModel}) : ${error?.message || "inconnue"}. Vérifiez \`ollama serve\` et \`ollama pull ${selectedModel}\`.`;
  }
}
