"use server";

import { revalidatePath } from "next/cache";
import { hasPermission } from "@/lib/adminAuth";
import { connectDB } from "@/lib/db";
import { OrderFeedback } from "@/models/OrderFeedback";
import { Testimonial } from "@/models/Testimonial";
import { QuickReview } from "@/models/QuickReview";
import { Client } from "@/models/Client";
import { DiscountCode } from "@/models/DiscountCode";
import { getSettings } from "@/lib/settings";
import { randomRewardCode } from "@/lib/rewardCode";
import { notifyRecipient } from "@/lib/notifications";
import { sendMailIfEnabled } from "@/lib/mail";
import { emailShell } from "@/lib/emailTemplate";

const FEEDBACK_ADMIN_PATH = "/de/admin/feedback";

type FormState = { error?: string; success?: boolean; rewardCode?: string };

// Kleiner Dank fürs Mühe machen — nur bei einem echten geschriebenen
// Kommentar (nicht schon bei einer reinen Sternebewertung ohne Text), siehe
// reviewRewardSettings. Fehler hier dürfen das eigentliche Feedback nicht
// verhindern, daher separat abgesichert statt die ganze Aktion abzubrechen.
async function grantReviewReward(
  client: { _id: string; name: string; email: string; locale: "de" | "en" }
): Promise<string | null> {
  try {
    const settings = await getSettings();
    if (!settings.reviewRewardSettings?.enabled) return null;

    let code = randomRewardCode();
    while (await DiscountCode.findOne({ code })) code = randomRewardCode();

    await DiscountCode.create({
      code,
      type: settings.reviewRewardSettings.type,
      value: settings.reviewRewardSettings.value,
      maxUses: 1,
      ownerId: client._id,
      active: true,
      note: "Dankeschön für eine geschriebene Bewertung.",
    });

    const isEn = client.locale === "en";
    const html = await emailShell({
      heading: `Hi ${client.name},`,
      bodyHtml: isEn
        ? `<p style="margin:0 0 8px;">Thank you so much for taking the time to write a review! As a small thank-you, here's a discount code for your next shoot:</p>
           <p style="margin:12px 0; font-size:1.2rem; letter-spacing:0.05em;"><strong>${code}</strong></p>`
        : `<p style="margin:0 0 8px;">Danke dir sehr fürs Zeitnehmen und Schreiben deiner Bewertung! Als kleines Dankeschön hier ein Rabattcode für dein nächstes Shooting:</p>
           <p style="margin:12px 0; font-size:1.2rem; letter-spacing:0.05em;"><strong>${code}</strong></p>`,
      buttonLabel: isEn ? "Book a new shoot" : "Neues Shooting anfragen",
      buttonUrl: `${process.env.SITE_URL}/${client.locale}/angebote`,
      footerNote: isEn ? "Thanks again for your feedback!" : "Nochmal danke für dein Feedback!",
    });
    await sendMailIfEnabled(client._id, client.email, isEn ? "Thank you — a little gift for you" : "Danke dir — ein kleines Geschenk", html);
    await notifyRecipient(client._id, {
      type: "review_reward",
      title: isEn ? "Thank you for your review!" : "Danke für deine Bewertung!",
      body: isEn ? `Discount code: ${code}` : `Rabattcode: ${code}`,
      link: `/${client.locale}/account`,
    });

    return code;
  } catch (err) {
    console.error("Bewertungs-Prämie fehlgeschlagen:", err);
    return null;
  }
}

// Öffentlich, kein Login nötig — der Token im Link ist der Zugangsschlüssel,
// analog zu /verify/[token] und /reset-password/[token].
export async function submitFeedbackAction(_prev: FormState, formData: FormData): Promise<FormState> {
  const token = String(formData.get("token") || "");
  const locale = String(formData.get("locale") || "de");
  const isEn = locale === "en";
  const rating = Number(formData.get("rating"));
  const comment = String(formData.get("comment") || "").trim();
  const allowTestimonial = formData.get("allowTestimonial") === "on";

  if (!token) return { error: isEn ? "Invalid link." : "Ungültiger Link." };
  if (!Number.isInteger(rating) || rating < 1 || rating > 5) {
    return { error: isEn ? "Please choose a rating from 1 to 5 stars." : "Bitte eine Bewertung von 1 bis 5 Sternen wählen." };
  }

  await connectDB();
  // Atomar per findOneAndUpdate mit submitted:false im Filter statt
  // findOne+save — verhindert, dass zwei nahezu gleichzeitige Einsendungen
  // (z. B. zwei offene Tabs) beide die submitted-Prüfung passieren und
  // doppelt einen Bewertungs-Rabattcode auslösen.
  const feedback = await OrderFeedback.findOneAndUpdate(
    { token, submitted: false },
    { $set: { rating, comment, allowTestimonial, submitted: true, submittedAt: new Date() } }
  );
  if (!feedback) {
    const exists = await OrderFeedback.exists({ token });
    if (!exists) return { error: isEn ? "This feedback link is invalid." : "Dieser Feedback-Link ist ungültig." };
    return { success: true };
  }

  let rewardCode: string | null = null;
  if (comment) {
    const client = await Client.findById(feedback.clientId).select("name firstName nickname email locale").lean();
    if (client) {
      rewardCode = await grantReviewReward({
        _id: String(client._id),
        name: client.nickname || client.firstName || client.name,
        email: client.email,
        locale: client.locale,
      });
    }
  }

  return { success: true, rewardCode: rewardCode || undefined };
}

export async function createTestimonialFromFeedbackAction(feedbackId: string) {
  if (!(await hasPermission("testimonials_create"))) return;
  await connectDB();
  const feedback = await OrderFeedback.findById(feedbackId);
  if (!feedback || !feedback.comment) return;

  // Bewusst nicht sofort sichtbar — Rakku soll Wortlaut/Kürzung erst
  // gegenlesen können, bevor eine Kundenstimme live auf der Startseite steht.
  await Testimonial.create({
    authorName: feedback.clientName,
    quote: feedback.comment,
    context: feedback.shootingType,
    rating: feedback.rating,
    visible: false,
    sortOrder: Date.now(),
  });
  feedback.usedForTestimonial = true;
  await feedback.save();

  revalidatePath(FEEDBACK_ADMIN_PATH);
  revalidatePath("/de/admin/testimonials");
}

// Getrennt von der Kundenstimme (Zitat) oben — deckt den Fall ab, dass ein
// Kunde nur Sterne ohne Text hinterlassen hat (dafür braucht es kein
// Gegenlesen, deshalb sofort sichtbar, kein Umweg über einen "unsichtbar"-
// Zwischenschritt). Das Team entscheidet mit diesem Klick bewusst, ob die
// Bewertung in den öffentlichen Durchschnitt einfließt — genau die
// Freigabe, die für den Fall von unglaubwürdigen/Fake-Bewertungen gewünscht
// ist, ohne dass der Kunde davon je etwas mitbekommt.
export async function createQuickReviewFromFeedbackAction(feedbackId: string) {
  if (!(await hasPermission("testimonials_create"))) return;
  await connectDB();
  const feedback = await OrderFeedback.findById(feedbackId);
  if (!feedback || !feedback.rating) return;

  await QuickReview.create({
    authorName: feedback.clientName,
    rating: feedback.rating,
    visible: true,
    sortOrder: Date.now(),
  });
  feedback.usedForQuickReview = true;
  await feedback.save();

  revalidatePath(FEEDBACK_ADMIN_PATH);
  revalidatePath("/de/admin/testimonials");
  revalidatePath("/de");
  revalidatePath("/en");
}
