/**
 * Generiert einen kontextualisierten Inhaltsvorschlag für eine Section-Instance.
 *
 * Pattern analog zu draft-brief.ts und suggest-hero/route.ts: OpenRouter mit Tool-Calling,
 * dediziertes Tool pro Section-Kind via System-Prompt, Output ist eine flache Struktur
 * (headline + lines), die der Caller zu TipTap konvertiert.
 *
 * USER-BEITRAGS-PUNKT (Plan §"Bewusste User-Beiträge" #2):
 * Die `KIND_PROMPTS` unten sind die Stelle wo deine Domain-Erfahrung am meisten zählt.
 * Ich habe Skelette mit den wichtigsten Constraints angelegt — feinjustiere die Wording-Richtlinien
 * für deine Cumas/KSM/Spartarif-Praxis.
 */

import OpenAI from 'openai';
import { jsonrepair } from 'jsonrepair';
import { z } from 'zod';
import { getOpenRouterKey, getOpenRouterKeyOptional } from "@/core/settings";

const DEFAULT_MODEL = 'anthropic/claude-sonnet-4.6';
const MAX_TOKENS = 1500;

export type SectionKind = 'contact_service' | 'app_download' | 'testimonial' | 'faq' | 'custom';

const SectionContentSchema = z.object({
  headline: z.string().min(2).max(120),
  lines: z.array(z.string().min(2).max(400)).min(1).max(8),
});
export type SectionContent = z.infer<typeof SectionContentSchema>;

const SECTION_TOOL: OpenAI.Chat.Completions.ChatCompletionTool = {
  type: 'function',
  function: {
    name: 'propose_section_content',
    description: 'Liefert headline + Zeilen für einen Section-Block (Kontakt, App, Testimonial, FAQ).',
    parameters: {
      type: 'object',
      required: ['headline', 'lines'],
      properties: {
        headline: { type: 'string', description: 'Kurze H3-Überschrift, 2-80 Zeichen' },
        lines: {
          type: 'array',
          items: { type: 'string' },
          minItems: 1,
          maxItems: 8,
          description: 'Zeilen/Paragraphen, jeweils 1 Satz oder 1 Zeile. Werden im UI als Paragraphs gerendert.',
        },
      },
    },
  },
};

const COMMON_RULES = `
# Allgemeine Regeln
- Sprache: matche die Sprache des Briefings (de/en). Bei Deutsch: Sie-Form (außer Briefing sagt explizit du).
- Keine Spam-Trigger: GRATIS, 100% kostenlos, JETZT KAUFEN, GARANTIERT — auch in Variationen.
- Keine ALL-CAPS-Wörter (außer Workspace-Namen).
- Max. 1 Ausrufezeichen pro Zeile.
- Nutze NICHT die Begriffe "Hero", "CTA" oder andere Marketing-Jargon — schreibe für End-Empfänger.
- Workspace-Voice und Wording-Style berücksichtigen wenn angegeben.
- Output: nur das Tool propose_section_content aufrufen, kein freier Text.
`.trim();

/**
 * USER-BEITRAGS-PUNKT: Pro Section-Kind ein eigener Prompt-Block.
 * Hier kannst du jeden Block nach deinem Geschmack feinjustieren — das ist die größte
 * Hebelwirkung auf die Qualität der KI-Vorschläge.
 */
const KIND_PROMPTS: Record<SectionKind, string> = {
  contact_service: `
Du bist Service-Texter. Schlage einen Kontakt/Service-Block vor.

# Pflicht-Elemente
- Headline: kurz und einladend ("Fragen? Wir helfen", "Persönliche Beratung", "Direkter Draht zu uns")
- Mindestens eine Telefonnummer ODER Email
- Optional: Öffnungszeiten / Servicezeiten
- Optional: Hinweis auf Antwortzeit oder Direktansprechpartner

# Stil
- Kurze Zeilen, jeweils 1 Information pro Zeile.
- KEINE generischen Floskeln wie "Wir sind für Sie da" als einzigen Inhalt — immer mit konkreter Kontaktinfo.
- Nutze die Workspace-Daten aus dem Kontext wenn vorhanden, sonst Platzhalter mit eckigen Klammern.
`,
  app_download: `
Du bist App-Marketing-Texter. Schlage einen App-Download-Block vor.

# Pflicht-Elemente
- Headline: nutzenorientiert ("Auch als App verfügbar", "Die ganze Service-Welt in der Tasche")
- 1-2 Zeilen die den App-Nutzen beschreiben (NICHT Features auflisten — Nutzen)
- Eine Zeile mit Hinweis auf App Store + Google Play (die Badge-Bilder werden später vom Template gerendert)

# Stil
- Sehr kurz halten — User soll auf einen Blick verstehen was die App bringt.
- Keine technischen Begriffe (iOS, Android-Version, etc.) — nur Nutzen.
`,
  testimonial: `
Du bist Conversion-Texter. Schlage einen Testimonial-Block vor.

# Pflicht-Elemente
- Headline: optional, sonst leer-String.
- Eine Zeile = das Zitat selbst (in Anführungszeichen)
- Eine Zeile = Attribution (Vorname Nachname, Rolle/Firma) — eckige Klammern für Platzhalter wenn nicht im Briefing.

# Stil
- Klingt wie echte Kunden-Sprache, nicht wie Marketing-Slogan.
- Konkrete Zahl ODER konkretes Ergebnis ist Pflicht im Zitat ("seit 3 Monaten", "30% schneller", "von 5 auf 0 Reklamationen").
- Wenn der Briefing einen socialProof-Text hat, baue darauf auf — nicht ignorieren.
`,
  faq: `
Du bist FAQ-Texter. Schlage einen kurzen FAQ-Block vor.

# Pflicht-Elemente
- Headline: "Häufige Fragen" oder kontextspezifisch ("Was Sie wissen sollten", "Drei wichtige Antworten")
- 2-3 Fragen, jeweils direkt gefolgt von der Antwort.
- Format pro FAQ: Zeile 1 = Frage (mit Fragezeichen), Zeile 2 = Antwort. Also 4-6 lines insgesamt für 2-3 FAQs.

# Stil
- Frage in Empfänger-Sprache ("Was kostet das?", "Wie lange dauert das?", "Brauche ich…?").
- Antwort konkret, max. 2 Sätze. Keine Marketing-Sprache.
- FAQs müssen sich auf das Angebot/Pain im Briefing beziehen — keine generischen FAQs.
`,
  custom: `
Du bist Marketing-Texter. Schlage einen passenden Section-Block vor basierend auf dem Section-Namen und dem Briefing.

# Pflicht-Elemente
- Headline passend zum Section-Zweck.
- 2-5 Zeilen Inhalt.
- Bei einem expliziten aiPromptHint im Kontext — folge dem strikt.
`,
};

export interface SuggestSectionInput {
  kind: SectionKind;
  /** Der menschen-lesbare Name der Section (bei custom besonders wichtig). */
  templateName: string;
  /** Optionaler Hint vom Template selbst (section_templates.aiPromptHint). */
  templateHint?: string;
  /** Briefing-Kontext zur Kontextualisierung. */
  briefingContext: {
    campaignName?: string;
    offer?: string;
    painPoint?: string;
    language?: 'auto' | 'de' | 'en';
    socialProof?: string;
  };
  workspace?: {
    name: string;
    senderName?: string;
    voice?: string;
    wordingStyle?: string;
  };
  /** Bei mode='refine' wird der existierende Inhalt mitgegeben damit die KI ihn feinjustiert statt neu schreibt. */
  mode: 'fresh' | 'refine';
  currentContentText?: string;
}

export interface SuggestSectionResult {
  content: SectionContent;
  modelUsed: string;
  tokensIn?: number;
  tokensOut?: number;
  durationMs: number;
}

export async function suggestSectionContent(input: SuggestSectionInput): Promise<SuggestSectionResult> {
  const start = Date.now();

  if (!getOpenRouterKeyOptional()) {
    return {
      content: produceStub(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 systemPrompt = `${KIND_PROMPTS[input.kind]}\n\n${COMMON_RULES}`;
  const userMsg = buildUserMessage(input);

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

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

  let args: Record<string, unknown>;
  try {
    args = JSON.parse(toolCall.function.arguments) as Record<string, unknown>;
  } catch {
    args = JSON.parse(jsonrepair(toolCall.function.arguments)) as Record<string, unknown>;
  }

  // Defensive Coercion: Sonnet variabel im Output. Wir akzeptieren:
  //  - lines als Array<string> (Glücksfall)
  //  - lines als String (Sonnet stringifyt das Array manchmal)
  //  - lines als Array<string|Array<string>> (Sonnet macht manchmal Q&A als nested array)
  //  - leere Strings die rausgefiltert werden
  args.lines = normalizeLines(args.lines);

  const parsed = SectionContentSchema.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 section content schema: ${issues}`);
  }

  return {
    content: parsed.data,
    modelUsed: model,
    tokensIn: completion.usage?.prompt_tokens,
    tokensOut: completion.usage?.completion_tokens,
    durationMs: Date.now() - start,
  };
}

/**
 * Coerce verschiedener Sonnet-Output-Formen auf string[]:
 *  - Array von Strings → unverändert (nur trim + leere droppen)
 *  - Array von Arrays → flatten (Q&A-Pattern wo Sonnet [["Q1","A1"],["Q2","A2"]] schickt)
 *  - String → JSON-parse-Versuch, sonst Newline-Split
 *  - Sonst: defensiver Fallback auf leere Liste (Zod wird sauber erroren)
 */
function normalizeLines(input: unknown): string[] {
  if (Array.isArray(input)) {
    const out: string[] = [];
    for (const item of input) {
      if (typeof item === 'string') {
        const t = item.trim();
        if (t) out.push(t);
      } else if (Array.isArray(item)) {
        for (const sub of item) {
          if (typeof sub === 'string') {
            const t = sub.trim();
            if (t) out.push(t);
          }
        }
      }
    }
    return out;
  }
  if (typeof input === 'string') {
    try {
      const reparsed = JSON.parse(input);
      if (Array.isArray(reparsed)) return normalizeLines(reparsed);
    } catch {
      try {
        const repaired = jsonrepair(input);
        const reparsed = JSON.parse(repaired);
        if (Array.isArray(reparsed)) return normalizeLines(reparsed);
      } catch {
        /* fallthrough to newline split */
      }
    }
    return input.split(/\n+/).map((s) => s.trim()).filter(Boolean);
  }
  return [];
}

function buildUserMessage(input: SuggestSectionInput): string {
  const lines: string[] = [];
  lines.push(`# Section`);
  lines.push(`Typ: ${input.kind}`);
  lines.push(`Template-Name: ${input.templateName}`);
  if (input.templateHint) lines.push(`Template-Hint: ${input.templateHint}`);

  lines.push(``, `# Briefing-Kontext`);
  const c = input.briefingContext;
  if (c.campaignName) lines.push(`Kampagne: ${c.campaignName}`);
  if (c.offer) lines.push(`Angebot: ${c.offer}`);
  if (c.painPoint) lines.push(`Schmerzpunkt: ${c.painPoint}`);
  if (c.socialProof) lines.push(`Social-Proof-Hinweis: ${c.socialProof}`);
  if (c.language && c.language !== 'auto') lines.push(`Sprache: ${c.language}`);

  if (input.workspace) {
    lines.push(``, `# Workspace`);
    lines.push(`Name: ${input.workspace.name}`);
    if (input.workspace.senderName) lines.push(`Absender: ${input.workspace.senderName}`);
    if (input.workspace.voice) lines.push(`Workspace-Voice: ${input.workspace.voice}`);
    if (input.workspace.wordingStyle) lines.push(`Wording-Style: ${input.workspace.wordingStyle}`);
  }

  if (input.mode === 'refine' && input.currentContentText) {
    lines.push(``, `# Aktueller Inhalt (verfeinern, nicht ersetzen)`);
    lines.push(input.currentContentText.slice(0, 1000));
    lines.push(``, `Behalte Substanz und Workspace-Stimme, optimiere Wording und Struktur.`);
  } else {
    lines.push(``, `Erstelle einen frischen Vorschlag der zum Briefing passt.`);
  }

  return lines.join('\n');
}

function produceStub(input: SuggestSectionInput): SectionContent {
  // Stub-Output für lokales Testing ohne OPENROUTER_API_KEY.
  // Generisch aber kind-aware.
  switch (input.kind) {
    case 'contact_service':
      return {
        headline: 'Fragen? Wir helfen.',
        lines: [
          'Telefon: 0800 123 456 · Mo–Fr 8–18 Uhr',
          'E-Mail: service@example.com',
          'Persönliche Beratung — wir antworten innerhalb eines Werktags.',
        ],
      };
    case 'app_download':
      return {
        headline: 'Auch als App verfügbar',
        lines: [
          'Alle Funktionen direkt am Handy — schnell, übersichtlich, ohne Login-Stress.',
          'Jetzt kostenlos im App Store oder bei Google Play laden.',
        ],
      };
    case 'testimonial':
      return {
        headline: '',
        lines: [
          '„Seit drei Monaten dabei und ich frage mich, warum ich nicht früher gewechselt bin."',
          '— [Vorname Nachname], [Stadt]',
        ],
      };
    case 'faq':
      return {
        headline: 'Häufige Fragen',
        lines: [
          'Was kostet das?',
          'Der Tarif startet bei [Preis] pro Monat — keine versteckten Kosten.',
          'Wie schnell geht es?',
          'In der Regel sind Sie in unter 5 Minuten startklar.',
        ],
      };
    case 'custom':
    default:
      return {
        headline: input.templateName,
        lines: [
          'Stub-Inhalt — ohne OPENROUTER_API_KEY ist hier ein Platzhalter.',
          input.templateHint ?? 'Setze das Env-Var, um echte KI-Vorschläge zu bekommen.',
        ],
      };
  }
}
