"use server";

import { revalidatePath } from "next/cache";
import { getServerSession } from "next-auth";
import { Op } from "sequelize";
import { authOptions } from "@/lib/auth/auth-options";
import { initDb } from "@/lib/db";
import { requireActiveUser } from "@/lib/auth/verify-session-user";
import { FEATURES } from "@/config/features";
import {
  consentChangeSchema,
  participantOnboardingSchema,
  setActiveModeSchema,
  updateParticipantProfileSchema,
  type ParticipantOnboardingInput,
  type UpdateParticipantProfileInput,
} from "@/lib/validation/participant";
import {
  CONSENT_KEYS,
  getCurrentPolicy,
  recordConsentDecision,
} from "@/lib/participant/consent";
import { landingPathForMode } from "@/lib/participant/capabilities";
import type { ActionResult } from "@/lib/actions/auth";
import type { ActiveMode } from "@/types/participant";

async function currentUser() {
  const session = await getServerSession(authOptions);
  if (!session?.user?.id) return null;
  return requireActiveUser(session.user.id);
}

/** Create (or reactivate) the caller's participant profile. */
export async function completeParticipantOnboarding(
  input: ParticipantOnboardingInput
): Promise<ActionResult<{ redirectTo: string }>> {
  if (!FEATURES.participantPlatform) {
    return { success: false, error: "Participant mode is not available" };
  }

  const user = await currentUser();
  if (!user) return { success: false, error: "Not authenticated" };
  if (user.role !== "client") {
    return { success: false, error: "This account cannot join as a participant" };
  }

  const parsed = participantOnboardingSchema.safeParse(input);
  if (!parsed.success) {
    return {
      success: false,
      error: parsed.error.issues[0]?.message ?? "Invalid input",
    };
  }
  const data = parsed.data;

  const { sequelize, ParticipantProfile, UserPreference, AuditLog } = initDb();

  try {
    await sequelize.transaction(async (t) => {
      const now = new Date();
      let profile = await ParticipantProfile.findOne({
        where: { userId: user.id },
        transaction: t,
        lock: t.LOCK.UPDATE,
      });

      const fields = {
        status: "active" as const,
        onboardingIntent: data.intent,
        countryCode: data.countryCode,
        regionCode: data.regionCode,
        ageBand: data.ageBand,
        onboardingCompletedAt: now,
        lastProfileReviewAt: now,
        closedAt: null,
      };

      if (profile) {
        await profile.update(
          { ...fields, profileVersion: profile.profileVersion + 1 },
          { transaction: t }
        );
      } else {
        profile = await ParticipantProfile.create(
          { userId: user.id, ...fields },
          { transaction: t }
        );
      }

      await recordConsentDecision(
        {
          participantProfileId: profile.id,
          policyKey: CONSENT_KEYS.participantTerms,
          status: "granted",
          source: "onboarding",
        },
        t
      );

      if (data.domesticFeedConsent) {
        await recordConsentDecision(
          {
            participantProfileId: profile.id,
            policyKey: CONSENT_KEYS.domesticFeed,
            status: "granted",
            source: "onboarding",
          },
          t
        );
      }

      // "Both" finishes creator onboarding next, so the creator mode wins.
      const activeMode: ActiveMode =
        data.intent === "both" && !user.workspaceId ? "creator" : "participant";
      const [prefs] = await UserPreference.findOrCreate({
        where: { userId: user.id },
        defaults: { userId: user.id, activeMode },
        transaction: t,
      });
      if (prefs.activeMode !== activeMode) {
        await prefs.update({ activeMode }, { transaction: t });
      }

      await AuditLog.create(
        {
          actorUserId: user.id,
          workspaceId: user.workspaceId ?? null,
          action: "participant.onboarded",
          metadata: {
            intent: data.intent,
            countryCode: data.countryCode,
            domesticFeedConsent: data.domesticFeedConsent,
          },
        },
        { transaction: t }
      );
    });
  } catch (err) {
    if (err instanceof Error && err.message === "POLICY_NOT_FOUND") {
      return { success: false, error: "Participant terms are not configured" };
    }
    return { success: false, error: "Failed to set up your participant profile" };
  }

  revalidatePath("/participant");
  revalidatePath("/onboarding");

  const redirectTo =
    data.intent === "both" && !user.workspaceId
      ? "/onboarding?intent=create"
      : "/participant";
  return { success: true, data: { redirectTo } };
}

/** Switch between Creator and Participant mode (capability re-checked). */
export async function setActiveMode(
  mode: ActiveMode
): Promise<ActionResult<{ redirectTo: string }>> {
  const parsed = setActiveModeSchema.safeParse({ mode });
  if (!parsed.success) return { success: false, error: "Invalid mode" };

  const user = await currentUser();
  if (!user) return { success: false, error: "Not authenticated" };

  const { UserPreference, ParticipantProfile } = initDb();

  if (parsed.data.mode === "creator" && !user.workspaceId) {
    return { success: false, error: "Set up a creator workspace first" };
  }
  if (parsed.data.mode === "participant") {
    if (!FEATURES.participantPlatform) {
      return { success: false, error: "Participant mode is not available" };
    }
    const profile = await ParticipantProfile.findOne({
      where: { userId: user.id, status: { [Op.in]: ["active", "paused"] } },
    });
    if (!profile) {
      return { success: false, error: "Join as a participant first" };
    }
  }

  const [prefs] = await UserPreference.findOrCreate({
    where: { userId: user.id },
    defaults: { userId: user.id, activeMode: parsed.data.mode },
  });
  if (prefs.activeMode !== parsed.data.mode) {
    await prefs.update({ activeMode: parsed.data.mode });
  }

  return {
    success: true,
    data: { redirectTo: landingPathForMode(parsed.data.mode) },
  };
}

export async function updateParticipantProfile(
  input: UpdateParticipantProfileInput
): Promise<ActionResult> {
  const user = await currentUser();
  if (!user) return { success: false, error: "Not authenticated" };

  const parsed = updateParticipantProfileSchema.safeParse(input);
  if (!parsed.success) {
    return {
      success: false,
      error: parsed.error.issues[0]?.message ?? "Invalid input",
    };
  }

  const { ParticipantProfile } = initDb();
  const profile = await ParticipantProfile.findOne({
    where: { userId: user.id, status: { [Op.in]: ["active", "paused"] } },
  });
  if (!profile) return { success: false, error: "Participant profile not found" };

  await profile.update({
    countryCode: parsed.data.countryCode,
    regionCode: parsed.data.regionCode,
    ageBand: parsed.data.ageBand,
    profileVersion: profile.profileVersion + 1,
    lastProfileReviewAt: new Date(),
  });

  revalidatePath("/participant/profile");
  return { success: true };
}

export async function changeConsent(input: {
  policyKey: string;
  grant: boolean;
}): Promise<ActionResult> {
  const user = await currentUser();
  if (!user) return { success: false, error: "Not authenticated" };

  const parsed = consentChangeSchema.safeParse(input);
  if (!parsed.success) return { success: false, error: "Invalid request" };

  const { ParticipantProfile, AuditLog } = initDb();
  const profile = await ParticipantProfile.findOne({
    where: { userId: user.id, status: { [Op.in]: ["active", "paused"] } },
  });
  if (!profile) return { success: false, error: "Participant profile not found" };

  const policy = await getCurrentPolicy(parsed.data.policyKey);
  if (!policy) return { success: false, error: "Unknown permission" };
  if (policy.isRequired && !parsed.data.grant) {
    return {
      success: false,
      error: "This permission is required. Close your participant profile instead.",
    };
  }

  await recordConsentDecision({
    participantProfileId: profile.id,
    policyKey: policy.key,
    status: parsed.data.grant ? "granted" : "withdrawn",
    source: "privacy_settings",
  });

  await AuditLog.create({
    actorUserId: user.id,
    workspaceId: null,
    action: parsed.data.grant
      ? "participant.consent_granted"
      : "participant.consent_withdrawn",
    metadata: { policyKey: policy.key, policyVersion: policy.version },
  });

  revalidatePath("/participant/profile");
  revalidatePath("/participant/domestic");
  return { success: true };
}

/** Pause or resume participation without closing the profile. */
export async function setParticipationPaused(
  paused: boolean
): Promise<ActionResult> {
  const user = await currentUser();
  if (!user) return { success: false, error: "Not authenticated" };

  const { ParticipantProfile } = initDb();
  const profile = await ParticipantProfile.findOne({
    where: { userId: user.id, status: { [Op.in]: ["active", "paused"] } },
  });
  if (!profile) return { success: false, error: "Participant profile not found" };

  await profile.update({ status: paused ? "paused" : "active" });
  revalidatePath("/participant", "layout");
  return { success: true };
}

/**
 * Close the participant profile. Answers are retained under their consent
 * retention rules; the user keeps their creator workspace (if any).
 */
export async function closeParticipantProfile(): Promise<
  ActionResult<{ redirectTo: string }>
> {
  const user = await currentUser();
  if (!user) return { success: false, error: "Not authenticated" };

  const {
    sequelize,
    ParticipantProfile,
    ParticipantQuestionQueue,
    UserPreference,
    AuditLog,
  } = initDb();

  const profile = await ParticipantProfile.findOne({ where: { userId: user.id } });
  if (!profile || profile.status === "closed") {
    return { success: false, error: "Participant profile not found" };
  }

  await sequelize.transaction(async (t) => {
    const now = new Date();
    await profile.update({ status: "closed", closedAt: now }, { transaction: t });
    await ParticipantQuestionQueue.update(
      { status: "expired", activeKey: null },
      {
        where: {
          participantProfileId: profile.id,
          status: { [Op.in]: ["queued", "served"] },
        },
        transaction: t,
      }
    );
    await UserPreference.update(
      { activeMode: "creator" },
      { where: { userId: user.id }, transaction: t }
    );
    await AuditLog.create(
      {
        actorUserId: user.id,
        workspaceId: null,
        action: "participant.closed",
        metadata: {},
      },
      { transaction: t }
    );
  });

  return {
    success: true,
    data: { redirectTo: user.workspaceId ? "/app/dashboard" : "/onboarding" },
  };
}
