import { createAdminClient } from "@/lib/supabase/admin";
import { getProvider } from "./rewrite-client";
import { getPersonaBySlug, pickPersonaForContent, type Persona } from "./personas";
import { runQualityGates } from "./quality-gates";

export interface RewriteOutcome {
  submissionId: string;
  rewriteJobId: string;
  rewrittenArticleId: string | null;
  status: "succeeded" | "failed_quality" | "failed_api";
  attempts: number;
  personaSlug: string;
  bannedWordsFound: string[];
  aiDetectorScore: number | null;
  failureReason: string | null;
  result?: {
    title: string;
    slug: string;
    excerpt: string;
    body: string;
    category: string;
    tags: string[];
  };
}

function slugify(title: string): string {
  const base = title
    .toLowerCase()
    .replace(/[^a-z0-9\s-]/g, "")
    .replace(/\s+/g, "-")
    .replace(/-+/g, "-")
    .replace(/^-|-$/g, "")
    .slice(0, 96);
  return `${base || "article"}-${Date.now().toString(36)}`;
}

async function readConfigInt(key: string, def: number): Promise<number> {
  try {
    const sb = createAdminClient();
    const { data } = await sb.from("ai_rewrite_config").select("value").eq("key", key).maybeSingle();
    const v = (data as any)?.value;
    if (typeof v === "number") return v;
    if (typeof v === "string") {
      const n = Number(v);
      if (!Number.isNaN(n)) return n;
    }
    if (v && typeof v === "object" && "value" in v) {
      const n = Number((v as any).value);
      if (!Number.isNaN(n)) return n;
    }
  } catch {}
  return def;
}

async function readConfigFloat(key: string, def: number): Promise<number> {
  return readConfigInt(key, def);
}

export interface RewriteOptions {
  submissionId: string;
  personaSlug?: string;
}

export async function rewriteSubmission(opts: RewriteOptions): Promise<RewriteOutcome> {
  const sb = createAdminClient();

  const { data: subRow, error: subErr } = await sb
    .from("ai_original_submissions")
    .select("*")
    .eq("id", opts.submissionId)
    .single();
  if (subErr || !subRow) throw new Error(`Submission ${opts.submissionId} not found: ${subErr?.message}`);
  const sub: any = subRow;

  let persona: Persona | null = null;
  if (opts.personaSlug) persona = await getPersonaBySlug(opts.personaSlug);
  if (!persona) persona = await pickPersonaForContent(`${sub.raw_title}\n${sub.raw_content}`);

  const maxAttempts = await readConfigInt("max_regeneration_attempts", 3);
  const detectorThreshold = await readConfigFloat("ai_detector_threshold", 0.65);

  const provider = getProvider();

  let attempt = 0;
  let lastJobId = "";
  let lastBanned: string[] = [];
  let lastScore: number | null = null;
  let lastReason: string | null = null;

  while (attempt < maxAttempts) {
    attempt += 1;

    const { data: jobRow, error: jobErr } = await sb
      .from("ai_rewrite_jobs")
      .insert({
        original_submission_id: sub.id,
        persona_id: persona.id,
        attempt_number: attempt,
        status: "pending",
      })
      .select()
      .single();
    if (jobErr || !jobRow) throw new Error(`Could not create rewrite job: ${jobErr?.message}`);
    lastJobId = (jobRow as any).id;

    let rewrite;
    try {
      rewrite = await provider.rewrite({
        persona,
        rawTitle: sub.raw_title,
        rawContent: sub.raw_content,
      });
    } catch (err: any) {
      lastReason = err.message || String(err);
      await sb.from("ai_rewrite_jobs").update({
        status: "failed_api",
        failure_reason: lastReason,
        finished_at: new Date().toISOString(),
      }).eq("id", lastJobId);
      continue;
    }

    const gates = await runQualityGates(rewrite.title, rewrite.body, rewrite.excerpt, detectorThreshold);

    await sb.from("ai_rewrite_jobs").update({
      generated_title: rewrite.title,
      generated_excerpt: rewrite.excerpt,
      generated_body: rewrite.body,
      generated_category: rewrite.category,
      generated_tags: rewrite.tags,
      ai_detector_score: gates.aiDetectorScore,
      banned_words_found: gates.bannedWordsFound,
      model: rewrite.model,
      input_tokens: rewrite.inputTokens,
      output_tokens: rewrite.outputTokens,
      cache_read_tokens: rewrite.cacheReadTokens,
      status: gates.passed ? "succeeded" : "failed_quality",
      failure_reason: gates.passed ? null : gates.reasons.join("; "),
      finished_at: new Date().toISOString(),
    }).eq("id", lastJobId);

    lastBanned = gates.bannedWordsFound;
    lastScore = gates.aiDetectorScore;
    lastReason = gates.passed ? null : gates.reasons.join("; ");

    if (!gates.passed) continue;

    const slug = slugify(rewrite.title);
    const { data: art, error: artErr } = await sb
      .from("ai_rewritten_articles")
      .insert({
        original_submission_id: sub.id,
        rewrite_job_id: lastJobId,
        persona_id: persona.id,
        slug,
        title: rewrite.title,
        excerpt: rewrite.excerpt,
        body: rewrite.body,
        category: rewrite.category,
        tags: rewrite.tags,
        status: "ai_rewritten_pending_review",
      })
      .select()
      .single();
    if (artErr || !art) throw new Error(`Could not save rewritten article: ${artErr?.message}`);

    // ── PUBLISH to wp_imported_posts so the /news pages actually serve the
    //    rewritten content. Without this step, ai_rewritten_articles fills
    //    up with rewrites that never surface publicly. Uses a negative wp_id
    //    so the rewrite doesn't collide with WP-imported sequence values.
    try {
      const featuredImage = sub.metadata?.featured_image_url || null;
      const authorName = persona.name || sub.contributor_name || "AV Beat";
      const finalSlug = `${slug}-rw-${(art as any).id.toString().slice(0, 6)}`;
      const wpRow = {
        wp_id: -Math.floor(Date.now() / 1000) - attempt,
        wp_slug: finalSlug,
        title: rewrite.title,
        excerpt: rewrite.excerpt,
        content: rewrite.body,
        author_name: authorName,
        category: rewrite.category || "News",
        tags: Array.isArray(rewrite.tags) ? rewrite.tags : [],
        featured_image: featuredImage,
        status: "published" as const,
        wp_published_at: new Date().toISOString(),
        imported_at: new Date().toISOString(),
        ai_rewritten_at: new Date().toISOString(),
        site_id: 1,
      };
      await sb.from("wp_imported_posts").insert(wpRow);
    } catch (publishErr: any) {
      // Don't fail the whole pipeline — the rewrite still landed in
      // ai_rewritten_articles. Just log so we can backfill later.
      console.warn(`[rewrite-pipeline] published rewrite ${(art as any).id} to ai_rewritten_articles but wp_imported_posts insert failed:`, publishErr?.message || publishErr);
    }

    return {
      submissionId: sub.id,
      rewriteJobId: lastJobId,
      rewrittenArticleId: (art as any).id,
      status: "succeeded",
      attempts: attempt,
      personaSlug: persona.slug,
      bannedWordsFound: gates.bannedWordsFound,
      aiDetectorScore: gates.aiDetectorScore,
      failureReason: null,
      result: {
        title: rewrite.title,
        slug,
        excerpt: rewrite.excerpt,
        body: rewrite.body,
        category: rewrite.category,
        tags: rewrite.tags,
      },
    };
  }

  return {
    submissionId: sub.id,
    rewriteJobId: lastJobId,
    rewrittenArticleId: null,
    status: lastReason && lastReason.startsWith("Anthropic API") ? "failed_api" : "failed_quality",
    attempts: attempt,
    personaSlug: persona.slug,
    bannedWordsFound: lastBanned,
    aiDetectorScore: lastScore,
    failureReason: lastReason,
  };
}

export async function ingestRawSubmission(input: {
  rawTitle: string;
  rawContent: string;
  rawHtml?: string;
  contributorEmail?: string;
  contributorName?: string;
  source?: string;
  metadata?: Record<string, unknown>;
}): Promise<string> {
  const sb = createAdminClient();
  const { data, error } = await sb
    .from("ai_original_submissions")
    .insert({
      raw_title: input.rawTitle,
      raw_content: input.rawContent,
      raw_html: input.rawHtml || null,
      contributor_email: input.contributorEmail || null,
      contributor_name: input.contributorName || null,
      source: input.source || "contributor_publish",
      metadata: input.metadata || {},
    })
    .select("id")
    .single();
  if (error || !data) throw new Error(`ingestRawSubmission: ${error?.message}`);
  return (data as any).id as string;
}
