import OpenAI from 'openai';
import { z } from 'zod';
import { sectionsToTiptap, type BriefSections, type Lang, type TipTapResult } from './sections-to-tiptap';
import { getOpenRouterKey, getOpenRouterKeyOptional } from "@/core/settings";

// Pin auf Sonnet 4.6 — gleiche Stelle wie suggest-briefing.ts und pipeline.ts.
// Tilde-Pointer ('~latest') würde bei Releases ungeprüft weiterrouten und Tool-Use-Verhalten ändern.
const DEFAULT_MODEL = 'anthropic/claude-sonnet-4.6';
// 4000 Tokens — ein kompletter Brief mit Headline, Pain, Solution, 5 Benefits, CTA, P.S. und Signatur
// liegt typischerweise bei 600-1200 Tokens. 4× Headroom für längere B2B-Texte oder strukturierte Listen.
const MAX_TOKENS = 4000;

// Schema lenient — die Min-Länge auf den Sektionen verhindert leere Strings, ohne dass das LLM
// in 422-Loops läuft. Headline und Benefits sind harte Pflicht (kein Brief ohne diese), alle anderen
// Felder bekommen sinnvolle Untergrenzen die "1 Wort" ausschließen.
const BriefSectionsSchema = z.object({
  headline: z.string().min(8).max(160),
  intro: z.string().min(15).max(600),
  pain_point: z.string().min(20).max(800),
  solution: z.string().min(20).max(800),
  benefits: z.array(z.string().min(5).max(200)).min(2).max(6),
  cta_paragraph: z.string().min(10).max(400),
  ps_line: z.string().min(5).max(300).optional(),
  signature: z.string().min(3).max(160),
});

const SYSTEM_PROMPT = `Du bist der Brief-Schreiber von MailForge. Aus einem strukturierten Briefing erzeugst du einen vorformulierten Marketing-Brief, der im Email-Editor des Users landet — als Eingabe für die spätere Mail-Pipeline.

# Was du NICHT machst (kritisch)
- KEIN Subject, KEIN Preheader, KEIN Hero-Bild-Brief — die produziert die Mail-Pipeline später aus deinem Brief.
- KEIN MJML, kein HTML — nur strukturierter Brief-Text in den definierten Sektionen.
- KEINE URLs erfinden. Keine konkreten Zahlen erfinden. Keine Deadlines außer im Briefing erwähnt.

# Sprache
- Erkenne die Sprache aus campaignName/offer/painPoint. Antworte in DERSELBEN Sprache.
- Bei Deutsch: Sie-Form (außer Briefing markiert explizit du). Bei Englisch: neutrale Anrede.

# Brief-Struktur (Sektionen-Output via Tool)
- "headline": kurze, nutzenorientierte Überschrift (8-80 Zeichen). Nicht das Subject — das macht die Pipeline. Eher eine Brief-Headline, die den Empfänger sofort einordnet.
- "intro": 1-2 Sätze persönliche Anrede. Verwende {{FIRST_NAME}} als Platzhalter für den Vornamen ("Hallo {{FIRST_NAME}}, …"). Sonst keine Platzhalter.
- "pain_point": 2-3 Sätze. Schmerzpunkt aus EMPFÄNGER-Sicht ausformuliert (nicht aus Anbieter-Sicht). Konkret, nicht generisch.
- "solution": 2-3 Sätze. Wie das Angebot den Schmerzpunkt löst. Nutzenorientiert, nicht featureorientiert.
- "benefits": 2-5 Bullets. Jeder Bullet 1 Satz, beginnt mit Verb oder klarem Nutzen. Konkrete Zahlen wenn aus Briefing ableitbar.
- "cta_paragraph": 1-2 Sätze die zum CTA hinleiten. Endet mit klarer Aufforderung (z.B. "Klicken Sie unten und sichern Sie sich Ihren Zugang."). Verwende den ctaPrimaryText aus dem Briefing als Aufforderungsphrase.
- "ps_line": optional, kurze P.S.-Zeile mit Zusatz-Argument oder Reminder. Sonst weglassen.
- "signature": 1-2 Zeilen Signatur (z.B. "Herzliche Grüße\\n{Workspace-Sender-Name}"). Nutze den brandSenderName aus dem Briefing.

# Anti-Spam-Regeln (HART)
- Keine Spam-Trigger: GRATIS, 100% kostenlos, JETZT KAUFEN, GELD VERDIENEN, RISIKOFREI, GARANTIERT, WINNER, limited time — auch in Variationen.
- Keine ALL-CAPS-Wörter (außer registrierten Workspace-Namen).
- Max. 1 Ausrufezeichen pro Sektion.

# Tonalität
- Nutzenorientiert, konkret, aktiv.
- Workspace-Voice und Wording-Style strikt einhalten (siehe User-Message).
- Kurze Absätze, keine Marketing-Floskeln.

# Output
Tool: write_brief. Liefere ALLE Pflicht-Sektionen. Kein freier Text außerhalb des Tool-Calls.`;

const WRITE_BRIEF_TOOL: OpenAI.Chat.Completions.ChatCompletionTool = {
  type: 'function',
  function: {
    name: 'write_brief',
    description: 'Liefert einen strukturierten Marketing-Brief aus dem Briefing als Sections.',
    parameters: {
      type: 'object',
      required: ['headline', 'intro', 'pain_point', 'solution', 'benefits', 'cta_paragraph', 'signature'],
      properties: {
        headline: { type: 'string', description: 'Brief-Headline (nicht Mail-Subject), 8-80 Zeichen' },
        intro: { type: 'string', description: 'Persönliche Anrede mit {{FIRST_NAME}}, 1-2 Sätze' },
        pain_point: { type: 'string', description: 'Schmerzpunkt aus Empfänger-Sicht, 2-3 Sätze' },
        solution: { type: 'string', description: 'Wie Angebot Pain löst, 2-3 Sätze' },
        benefits: { type: 'array', items: { type: 'string' }, minItems: 2, maxItems: 5, description: '2-5 Bullets, jeder 1 Satz' },
        cta_paragraph: { type: 'string', description: '1-2 Sätze die zum CTA hinleiten' },
        ps_line: { type: 'string', description: 'Optional P.S.-Zeile (Zusatz-Argument / Reminder)' },
        signature: { type: 'string', description: '1-2 Zeilen Signatur mit Workspace-Sender' },
      },
    },
  },
};

export interface DraftBriefInput {
  campaignName: string;
  offer: string;
  painPoint: string;
  ctaPrimaryText: string;
  heroBriefHint?: string;
  language?: 'auto' | 'de' | 'en';
  // Workspace-Kontext aus DB
  brandName: string;
  brandSenderName: string;
  brandVoice?: string;
  brandWordingStyle?: string;
  // Optionaler Scrape-Kontext für mehr Inspiration (kein Pflicht-Input)
  scrapeContext?: {
    title?: string;
    description?: string;
    headlines?: string[];
    bodyText?: string;
  };
}

export interface DraftBriefResult {
  sections: BriefSections;
  tiptap: TipTapResult;
  modelUsed: string;
  tokensIn?: number;
  tokensOut?: number;
  durationMs: number;
}

export async function draftBrief(input: DraftBriefInput): Promise<DraftBriefResult> {
  const start = Date.now();

  if (!getOpenRouterKeyOptional()) {
    const sections = produceStubBrief(input);
    return {
      sections,
      tiptap: sectionsToTiptap(sections, resolveLang(input)),
      modelUsed: 'stub-no-api-key',
      durationMs: Date.now() - start,
    };
  }

  const model = process.env.OPENROUTER_MODEL ?? DEFAULT_MODEL;
  const client = new OpenAI({
    baseURL: 'https://openrouter.ai/api/v1',
    apiKey: getOpenRouterKey(),
    defaultHeaders: {
      'HTTP-Referer': process.env.OPENROUTER_APP_URL ?? 'http://localhost:3000',
      'X-Title': process.env.OPENROUTER_APP_TITLE ?? 'MailForge',
    },
  });

  const userMsg = buildUserMessage(input);

  const completion = await client.chat.completions.create({
    model,
    max_tokens: MAX_TOKENS,
    messages: [
      { role: 'system', content: SYSTEM_PROMPT },
      { role: 'user', content: userMsg },
    ],
    tools: [WRITE_BRIEF_TOOL],
    tool_choice: { type: 'function', function: { name: 'write_brief' } },
  });

  const toolCall = completion.choices[0]?.message?.tool_calls?.[0];
  if (!toolCall || toolCall.type !== 'function') {
    throw new Error('Model returned no write_brief tool call');
  }

  const args = JSON.parse(toolCall.function.arguments);
  const parsed = BriefSectionsSchema.safeParse(args);
  if (!parsed.success) {
    const issues = parsed.error.issues.slice(0, 3).map((i) => `${i.path.join('.')}: ${i.message}`).join('; ');
    throw new Error(`Invalid brief schema: ${issues}`);
  }

  const sections = parsed.data;
  return {
    sections,
    tiptap: sectionsToTiptap(sections, resolveLang(input)),
    modelUsed: model,
    tokensIn: completion.usage?.prompt_tokens,
    tokensOut: completion.usage?.completion_tokens,
    durationMs: Date.now() - start,
  };
}

function buildUserMessage(input: DraftBriefInput): string {
  const lines: string[] = [];
  lines.push(`# Briefing`);
  lines.push(`- Kampagne: ${input.campaignName}`);
  lines.push(`- Angebot: ${input.offer}`);
  lines.push(`- Schmerzpunkt: ${input.painPoint}`);
  lines.push(`- CTA-Wording (für cta_paragraph): "${input.ctaPrimaryText}"`);
  if (input.heroBriefHint) lines.push(`- Hero-Hinweis (NUR Kontext, NICHT in Brief schreiben): ${input.heroBriefHint}`);
  if (input.language && input.language !== 'auto') lines.push(`- Sprache: ${input.language}`);

  lines.push(``);
  lines.push(`# Workspace`);
  lines.push(`- Workspace: ${input.brandName}`);
  lines.push(`- Absender für Signatur: ${input.brandSenderName}`);
  if (input.brandVoice) lines.push(`- Workspace-Voice: ${input.brandVoice}`);
  if (input.brandWordingStyle) lines.push(`- Wording-Style: ${input.brandWordingStyle}`);

  if (input.scrapeContext && (input.scrapeContext.title || input.scrapeContext.bodyText)) {
    lines.push(``);
    lines.push(`# Webseiten-Kontext (optional, als Inspiration für Wording)`);
    if (input.scrapeContext.title) lines.push(`- Title: ${input.scrapeContext.title}`);
    if (input.scrapeContext.description) lines.push(`- Description: ${input.scrapeContext.description}`);
    if (input.scrapeContext.headlines && input.scrapeContext.headlines.length > 0) {
      lines.push(`- Headlines: ${input.scrapeContext.headlines.slice(0, 8).join(' | ')}`);
    }
    if (input.scrapeContext.bodyText) {
      // Body auf 1500 chars cappen — der Body-Text vom Scrape ist primär Kontext, kein Vollzitat.
      const trimmed = input.scrapeContext.bodyText.slice(0, 1500);
      lines.push(`- Body-Auszug: ${trimmed}`);
    }
  }

  lines.push(``);
  lines.push(`Schreibe den Brief via write_brief-Tool. Antworte in der Sprache des Briefings.`);
  return lines.join('\n');
}

function resolveLang(input: DraftBriefInput): Lang {
  if (input.language === 'en') return 'en';
  if (input.language === 'de') return 'de';
  // Auto-Heuristik: prüfe campaignName/offer/painPoint auf typische deutsche Wörter.
  const sample = `${input.campaignName} ${input.offer} ${input.painPoint}`.toLowerCase();
  const hasGermanMarker = /[äöüß]|(\b(und|der|die|das|für|mit|sind|wird|nicht|sich|von|zum|zur)\b)/.test(sample);
  return hasGermanMarker ? 'de' : 'en';
}

function produceStubBrief(input: DraftBriefInput): BriefSections {
  const lang = resolveLang(input);
  if (lang === 'en') {
    return {
      headline: `[Stub] ${input.campaignName}`,
      intro: `Hi {{FIRST_NAME}}, this is a placeholder brief — set OPENROUTER_API_KEY for the real AI draft.`,
      pain_point: input.painPoint,
      solution: input.offer,
      benefits: ['Placeholder benefit 1', 'Placeholder benefit 2'],
      cta_paragraph: `Click below to ${input.ctaPrimaryText.toLowerCase()}.`,
      ps_line: undefined,
      signature: `Best regards,\n${input.brandSenderName}`,
    };
  }
  return {
    headline: `[Stub] ${input.campaignName}`,
    intro: `Hallo {{FIRST_NAME}}, das ist ein Platzhalter-Brief — setze OPENROUTER_API_KEY für die echte KI-Generierung.`,
    pain_point: input.painPoint,
    solution: input.offer,
    benefits: ['Platzhalter-Vorteil 1', 'Platzhalter-Vorteil 2'],
    cta_paragraph: `Klicken Sie unten und ${input.ctaPrimaryText.toLowerCase()}.`,
    ps_line: undefined,
    signature: `Herzliche Grüße,\n${input.brandSenderName}`,
  };
}
