"use server";

import { revalidatePath } from "next/cache";
import { initDb } from "@/lib/db";
import { requireClientWorkspace } from "@/lib/auth/require-auth";
import { getScopedSurvey } from "@/lib/queries/survey-queries";
import { getQuestionTypeConfig } from "@/config/question-types";
import {
  createQuestionSchema,
  updateQuestionSchema,
  reorderQuestionsSchema,
  deleteQuestionSchema,
  logicRuleSchema,
  updateSurveyWelcomeSchema,
  updateSurveyDisplaySchema,
  updateSurveyThankYouSchema,
} from "@/lib/validation/question";
import type { ActionResult } from "@/lib/actions/auth";

function revalidateBuilder(surveyId: string) {
  revalidatePath(`/app/surveys/${surveyId}/build`);
  revalidatePath(`/app/surveys/${surveyId}/preview`);
  revalidatePath("/app/dashboard");
  revalidatePath("/app/surveys");
  void revalidatePublicSurveyPages(surveyId);
}

async function revalidatePublicSurveyPages(surveyId: string) {
  const { Collector } = initDb();
  const collectors = await Collector.findAll({
    where: { surveyId },
    attributes: ["slug"],
  });
  for (const collector of collectors) {
    revalidatePath(`/s/${collector.slug}`);
  }
}

/** Add a new question to a survey. */
export async function addQuestion(
  surveyId: string,
  type: string
): Promise<ActionResult<{ questionId: string }>> {
  const { userId, workspaceId } = await requireClientWorkspace();
  const parsed = createQuestionSchema.safeParse({ surveyId, type });
  if (!parsed.success) {
    return { success: false, error: "Invalid input" };
  }

  const survey = await getScopedSurvey(surveyId, workspaceId);
  if (!survey) return { success: false, error: "Survey not found" };

  const { Question, AuditLog } = initDb();
  const config = getQuestionTypeConfig(parsed.data.type);
  if (!config) return { success: false, error: "Invalid question type" };

  const maxPosition = await Question.max("position", {
    where: { surveyId },
  });
  const position = (typeof maxPosition === "number" ? maxPosition : -1) + 1;

  const question = await Question.create({
    surveyId,
    type: parsed.data.type,
    title: config.defaultTitle,
    position,
    optionsConfig: config.defaultOptions,
    isRequired: false,
    randomizeOptions: false,
  });

  await AuditLog.create({
    actorUserId: userId,
    workspaceId,
    action: "question.created",
    metadata: { surveyId, questionId: question.id, type },
  });

  revalidateBuilder(surveyId);
  return { success: true, data: { questionId: question.id } };
}

/** Update question fields (title, options, validation, etc.). */
export async function updateQuestion(
  input: {
    surveyId: string;
    questionId: string;
    title?: string;
    isRequired?: boolean;
    randomizeOptions?: boolean;
    optionsConfig?: import("@/types").QuestionOptionsConfig | null;
    validationConfig?: import("@/types").QuestionValidationConfig | null;
  }
): Promise<ActionResult> {
  const { userId, workspaceId } = await requireClientWorkspace();
  const parsed = updateQuestionSchema.safeParse(input);
  if (!parsed.success) {
    return { success: false, error: "Invalid input" };
  }

  const survey = await getScopedSurvey(parsed.data.surveyId, workspaceId);
  if (!survey) return { success: false, error: "Survey not found" };

  const { Question, AuditLog } = initDb();
  const question = await Question.findOne({
    where: { id: parsed.data.questionId, surveyId: parsed.data.surveyId },
  });
  if (!question) return { success: false, error: "Question not found" };

  question.set({
    ...(parsed.data.title !== undefined && { title: parsed.data.title }),
    ...(parsed.data.isRequired !== undefined && {
      isRequired: parsed.data.isRequired,
    }),
    ...(parsed.data.randomizeOptions !== undefined && {
      randomizeOptions: parsed.data.randomizeOptions,
    }),
    ...(parsed.data.optionsConfig !== undefined && {
      optionsConfig: parsed.data.optionsConfig,
    }),
    ...(parsed.data.validationConfig !== undefined && {
      validationConfig: parsed.data.validationConfig,
    }),
  });
  // MySQL JSON columns often skip UPDATE unless explicitly marked dirty.
  if (parsed.data.optionsConfig !== undefined) {
    question.changed("optionsConfig", true);
  }
  if (parsed.data.validationConfig !== undefined) {
    question.changed("validationConfig", true);
  }
  await question.save();

  await AuditLog.create({
    actorUserId: userId,
    workspaceId,
    action: "question.updated",
    metadata: {
      surveyId: parsed.data.surveyId,
      questionId: parsed.data.questionId,
    },
  });

  revalidateBuilder(parsed.data.surveyId);
  return { success: true };
}

/** Reorder questions by ID list. */
export async function reorderQuestions(
  surveyId: string,
  orderedIds: string[]
): Promise<ActionResult> {
  const { workspaceId } = await requireClientWorkspace();
  const parsed = reorderQuestionsSchema.safeParse({ surveyId, orderedIds });
  if (!parsed.success) {
    return { success: false, error: "Invalid input" };
  }

  const survey = await getScopedSurvey(surveyId, workspaceId);
  if (!survey) return { success: false, error: "Survey not found" };

  const { sequelize, Question } = initDb();

  await sequelize.transaction(async (t) => {
    await Promise.all(
      orderedIds.map((id, index) =>
        Question.update(
          { position: index },
          { where: { id, surveyId }, transaction: t }
        )
      )
    );
  });

  revalidateBuilder(surveyId);
  return { success: true };
}

/** Delete a question from a survey. */
export async function deleteQuestion(
  surveyId: string,
  questionId: string
): Promise<ActionResult> {
  const { userId, workspaceId } = await requireClientWorkspace();
  const parsed = deleteQuestionSchema.safeParse({ surveyId, questionId });
  if (!parsed.success) {
    return { success: false, error: "Invalid input" };
  }

  const survey = await getScopedSurvey(surveyId, workspaceId);
  if (!survey) return { success: false, error: "Survey not found" };

  const { Question, AuditLog } = initDb();
  const question = await Question.findOne({
    where: { id: questionId, surveyId },
  });
  if (!question) return { success: false, error: "Question not found" };

  await question.destroy();

  await AuditLog.create({
    actorUserId: userId,
    workspaceId,
    action: "question.deleted",
    metadata: { surveyId, questionId },
  });

  revalidateBuilder(surveyId);
  return { success: true };
}

/** Upsert branching logic for a question (replaces existing rules). */
export async function upsertLogicRule(input: {
  surveyId: string;
  questionId: string;
  conditionType: "equals" | "not_equals" | "any_answer";
  conditionValue?: string | null;
  action: "skip_to_question" | "end_survey";
  targetQuestionId?: string | null;
}): Promise<ActionResult> {
  const { userId, workspaceId } = await requireClientWorkspace();
  const parsed = logicRuleSchema.safeParse(input);
  if (!parsed.success) {
    return { success: false, error: "Invalid input" };
  }

  const survey = await getScopedSurvey(parsed.data.surveyId, workspaceId);
  if (!survey) return { success: false, error: "Survey not found" };

  const { Question, LogicRule, AuditLog } = initDb();
  const question = await Question.findOne({
    where: { id: parsed.data.questionId, surveyId: parsed.data.surveyId },
  });
  if (!question) return { success: false, error: "Question not found" };

  await LogicRule.destroy({ where: { questionId: parsed.data.questionId } });

  if (
    parsed.data.conditionType !== "any_answer" ||
    parsed.data.action !== "skip_to_question" ||
    parsed.data.targetQuestionId
  ) {
    await LogicRule.create({
      questionId: parsed.data.questionId,
      conditionType: parsed.data.conditionType,
      conditionValue: parsed.data.conditionValue ?? null,
      action: parsed.data.action,
      targetQuestionId:
        parsed.data.action === "skip_to_question"
          ? (parsed.data.targetQuestionId ?? null)
          : null,
    });
  }

  await AuditLog.create({
    actorUserId: userId,
    workspaceId,
    action: "logic_rule.updated",
    metadata: {
      surveyId: parsed.data.surveyId,
      questionId: parsed.data.questionId,
    },
  });

  revalidateBuilder(parsed.data.surveyId);
  return { success: true };
}

/** Update survey welcome header shown on builder canvas. */
export async function updateSurveyWelcome(input: {
  surveyId: string;
  title: string;
  description?: string;
}): Promise<ActionResult> {
  const { userId, workspaceId } = await requireClientWorkspace();
  const parsed = updateSurveyWelcomeSchema.safeParse(input);
  if (!parsed.success) {
    return { success: false, error: "Invalid input" };
  }

  const survey = await getScopedSurvey(parsed.data.surveyId, workspaceId);
  if (!survey) return { success: false, error: "Survey not found" };

  const existingWelcome = survey.welcomeScreenConfig ?? {};
  await survey.update({
    title: parsed.data.title,
    description: parsed.data.description ?? survey.description,
    welcomeScreenConfig: {
      // Only carry over known safe fields — never spread unknown data
      buttonLabel: existingWelcome.buttonLabel ?? "Start survey",
      title: parsed.data.title,
      description:
        parsed.data.description ??
        existingWelcome.description ??
        "Help us improve. This survey takes about 2 minutes.",
    },
  });

  const { AuditLog } = initDb();
  await AuditLog.create({
    actorUserId: userId,
    workspaceId,
    action: "survey.welcome_updated",
    metadata: { surveyId: parsed.data.surveyId },
  });

  revalidateBuilder(parsed.data.surveyId);
  return { success: true };
}

/** Save how respondents see the survey: one-at-a-time, all-on-one-page, or grouped pages. */
export async function updateSurveyDisplay(input: {
  surveyId: string;
  layout: "one_per_page" | "single_page" | "grouped";
  pageBreakAfterIds?: string[];
}): Promise<ActionResult> {
  const { userId, workspaceId } = await requireClientWorkspace();
  const parsed = updateSurveyDisplaySchema.safeParse(input);
  if (!parsed.success) {
    return { success: false, error: "Invalid input" };
  }

  const survey = await getScopedSurvey(parsed.data.surveyId, workspaceId);
  if (!survey) return { success: false, error: "Survey not found" };

  const displayConfig = {
    layout: parsed.data.layout,
    pageBreakAfterIds: parsed.data.pageBreakAfterIds ?? [],
  };

  const { Survey, AuditLog } = initDb();
  await Survey.update(
    { displayConfig },
    { where: { id: parsed.data.surveyId, workspaceId } }
  );

  const saved = await Survey.findOne({
    where: { id: parsed.data.surveyId, workspaceId },
    attributes: ["id", "displayConfig"],
  });
  if (saved?.displayConfig?.layout !== displayConfig.layout) {
    return { success: false, error: "Failed to save layout" };
  }

  await AuditLog.create({
    actorUserId: userId,
    workspaceId,
    action: "survey.display_updated",
    metadata: { surveyId: parsed.data.surveyId, layout: parsed.data.layout },
  });

  revalidateBuilder(parsed.data.surveyId);
  await revalidatePublicSurveyPages(parsed.data.surveyId);
  return { success: true };
}

/** Save the default thank-you screen and optional answer-based variants. */
export async function updateSurveyThankYou(input: {
  surveyId: string;
  emoji?: string;
  title: string;
  description?: string;
  variants?: {
    id: string;
    questionId: string;
    conditionType: "equals" | "not_equals" | "any_answer";
    conditionValue: string | null;
    emoji: string;
    title: string;
    description: string;
  }[];
}): Promise<ActionResult> {
  const { userId, workspaceId } = await requireClientWorkspace();
  const parsed = updateSurveyThankYouSchema.safeParse(input);
  if (!parsed.success) {
    return { success: false, error: "Invalid input" };
  }

  const survey = await getScopedSurvey(parsed.data.surveyId, workspaceId);
  if (!survey) return { success: false, error: "Survey not found" };

  const thankYouScreenConfig = {
    emoji: parsed.data.emoji ?? "✅",
    title: parsed.data.title,
    description:
      parsed.data.description ?? "Your response has been recorded.",
    variants: parsed.data.variants ?? [],
  };

  const { Survey, AuditLog } = initDb();
  await Survey.update(
    { thankYouScreenConfig },
    { where: { id: parsed.data.surveyId, workspaceId } }
  );

  await AuditLog.create({
    actorUserId: userId,
    workspaceId,
    action: "survey.thank_you_updated",
    metadata: { surveyId: parsed.data.surveyId },
  });

  revalidateBuilder(parsed.data.surveyId);
  await revalidatePublicSurveyPages(parsed.data.surveyId);
  return { success: true };
}
