"use server";

import { and, eq } from "drizzle-orm";
import { revalidatePath } from "next/cache";
import { headers } from "next/headers";
import { z } from "zod";

import { auth } from "@/lib/auth";
import { requireOrgMember, requireOrgSession } from "@/lib/auth-guards";
import { db } from "@/lib/db";
import { member } from "@/lib/db/schema";

const SwitchSchema = z.object({ organizationId: z.string().min(1) });

export async function switchActiveOrganization(input: { organizationId: string }) {
  await requireOrgSession();
  const { organizationId } = SwitchSchema.parse(input);

  await auth.api.setActiveOrganization({
    headers: await headers(),
    body: { organizationId },
  });
  revalidatePath("/", "layout");
}

const CreateSchema = z.object({
  name: z.string().trim().min(1).max(80),
  slug: z.string().trim().min(1).max(80).optional(),
});

function slugify(input: string): string {
  const base = input
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, "-")
    .replace(/(^-|-$)/g, "")
    .slice(0, 50);
  return base || `org-${Date.now()}`;
}

export async function createOrganization(input: { name: string; slug?: string }) {
  await requireOrgSession();
  const parsed = CreateSchema.parse(input);

  const result = await auth.api.createOrganization({
    headers: await headers(),
    body: { name: parsed.name, slug: parsed.slug ?? slugify(parsed.name) },
  });
  if (!result) throw new Error("Failed to create organization");

  await auth.api.setActiveOrganization({
    headers: await headers(),
    body: { organizationId: result.id },
  });
  revalidatePath("/", "layout");
  return result;
}

const InvitationIdSchema = z.object({ invitationId: z.string().min(1) });

export async function acceptInvitation(input: { invitationId: string }) {
  await requireOrgSession();
  const { invitationId } = InvitationIdSchema.parse(input);

  const result = await auth.api.acceptInvitation({
    headers: await headers(),
    body: { invitationId },
  });
  if (result?.invitation?.organizationId) {
    await auth.api.setActiveOrganization({
      headers: await headers(),
      body: { organizationId: result.invitation.organizationId },
    });
  }
  revalidatePath("/", "layout");
  return result;
}

export async function rejectInvitation(input: { invitationId: string }) {
  await requireOrgSession();
  const { invitationId } = InvitationIdSchema.parse(input);

  await auth.api.rejectInvitation({
    headers: await headers(),
    body: { invitationId },
  });
}

/* Phase 4 org-level actions. */

const UpdateOrgSchema = z.object({
  name: z.string().trim().min(1).max(80),
  logo: z.string().trim().url().or(z.literal("")).optional(),
});

export async function updateOrganization(input: { name: string; logo?: string }) {
  const { activeOrganizationId } = await requireOrgMember({ minRole: "admin" });
  const parsed = UpdateOrgSchema.parse(input);

  await auth.api.updateOrganization({
    headers: await headers(),
    body: {
      organizationId: activeOrganizationId,
      data: {
        name: parsed.name,
        logo: parsed.logo || undefined,
      },
    },
  });
  revalidatePath("/settings/organization");
  revalidatePath("/", "layout");
}

export async function deleteOrganization() {
  const { activeOrganizationId } = await requireOrgMember({ minRole: "owner" });
  await auth.api.deleteOrganization({
    headers: await headers(),
    body: { organizationId: activeOrganizationId },
  });
  revalidatePath("/", "layout");
}

const TransferOwnershipSchema = z.object({ toMemberId: z.string().min(1) });

export async function transferOwnership(input: { toMemberId: string }) {
  const { activeOrganizationId, user: currentUser } = await requireOrgMember({ minRole: "owner" });
  const { toMemberId } = TransferOwnershipSchema.parse(input);

  // Find the current user's own member row in this org so we can demote them.
  const currentMemberRow = await db
    .select({ id: member.id })
    .from(member)
    .where(and(eq(member.userId, currentUser.id), eq(member.organizationId, activeOrganizationId)))
    .limit(1);
  if (currentMemberRow.length === 0) {
    throw new Error("Current owner membership row not found");
  }
  const currentMemberId = currentMemberRow[0]!.id;

  if (currentMemberId === toMemberId) {
    throw new Error("Cannot transfer ownership to yourself");
  }

  // Promote target, then demote current owner. Better Auth's API doesn't
  // expose a single atomic "transfer" — we do them sequentially. If the
  // demote fails, the org temporarily has two owners; that's a recoverable
  // state (a manual updateMemberRole call can fix it).
  await auth.api.updateMemberRole({
    headers: await headers(),
    body: {
      organizationId: activeOrganizationId,
      memberId: toMemberId,
      role: "owner",
    },
  });
  await auth.api.updateMemberRole({
    headers: await headers(),
    body: {
      organizationId: activeOrganizationId,
      memberId: currentMemberId,
      role: "admin",
    },
  });

  revalidatePath("/settings/organization");
  revalidatePath("/settings/team");
}
