import { createHash } from "node:crypto";
import { Prisma } from "@prisma/client";
import { OrganizationRole } from "@prisma/client";
import { db } from "@/lib/db";
import { getEnv } from "@/lib/env";
import { isRequestSignatureValid, isSignedRequestAuthorized } from "@/lib/security/hmac-signature";

export type WooSsoPayload = {
  customerId: string;
  email: string;
  name?: string;
  organizationName?: string;
  nonce: string;
  issuedAt: string;
  subscription?: {
    providerSubscriptionId: string;
    planCode: string;
    status: "TRIALING" | "ACTIVE" | "PAST_DUE" | "CANCELED" | "EXPIRED" | "SUSPENDED";
    billingInterval: "MONTHLY" | "ANNUAL" | "LIFETIME";
    currentPeriodEnd?: string | null;
    trialEndsAt?: string | null;
  };
};

export type WooAccountInput = Omit<WooSsoPayload, "nonce" | "issuedAt">;

function hashNonce(nonce: string) {
  return createHash("sha256").update(nonce).digest("hex");
}

function organizationName(payload: WooAccountInput) {
  return payload.organizationName?.trim() || payload.name?.trim() || payload.email.split("@")[0] || "My workspace";
}

function organizationSlug(customerId: string) {
  return `woo-${customerId.toLowerCase().replace(/[^a-z0-9]+/g, "-").slice(0, 40)}`;
}

export function verifyWooSsoRequest(request: Request, rawBody: string) {
  const secret = getEnv().WOO_SSO_SHARED_SECRET;
  return !!secret && isSignedRequestAuthorized(request, rawBody, secret);
}

export function verifyWooSsoPayload(rawPayload: string, signature: string) {
  const secret = getEnv().WOO_SSO_SHARED_SECRET;
  return !!secret && isRequestSignatureValid(rawPayload, signature, secret);
}

export function isFreshWooSsoIssue(issuedAt: string) {
  const issued = Date.parse(issuedAt);
  if (Number.isNaN(issued)) return false;
  return Math.abs(Date.now() - issued) <= getEnv().REQUEST_SIGNATURE_MAX_AGE_SECONDS * 1000;
}

export async function upsertWooAccount(payload: WooAccountInput) {
  const email = payload.email.trim().toLowerCase();

  return db.$transaction(async (tx) => {
    const existingByCustomer = await tx.user.findUnique({ where: { wooCustomerId: payload.customerId } });
    const existingByEmail = existingByCustomer ? null : await tx.user.findUnique({ where: { email } });
    if (existingByEmail?.wooCustomerId && existingByEmail.wooCustomerId !== payload.customerId) {
      throw new Error("This email is already linked to another WooCommerce customer. Contact support before signing in.");
    }
    const user = existingByCustomer ?? existingByEmail
      ? await tx.user.update({
          where: { id: (existingByCustomer ?? existingByEmail)!.id },
          data: { email, wooCustomerId: payload.customerId, name: payload.name?.trim() || undefined },
        })
      : await tx.user.create({ data: { email, wooCustomerId: payload.customerId, name: payload.name?.trim() || null } });

    const organization = await tx.organization.upsert({
      where: { slug: organizationSlug(payload.customerId) },
      update: {
        billingContactName: payload.name?.trim() || undefined,
        billingContactEmail: email,
      },
      create: {
        name: organizationName(payload),
        slug: organizationSlug(payload.customerId),
        billingContactName: payload.name?.trim() || null,
        billingContactEmail: email,
      },
    });

    await tx.organizationMember.upsert({
      where: { organizationId_userId: { organizationId: organization.id, userId: user.id } },
      update: {},
      create: { organizationId: organization.id, userId: user.id, role: OrganizationRole.OWNER },
    });

    return { userId: user.id, email: user.email, organizationId: organization.id };
  });
}

export async function exchangeWooSso(payload: WooSsoPayload) {
  const nonceHash = hashNonce(payload.nonce);
  const expiresAt = new Date(Date.now() + getEnv().REQUEST_SIGNATURE_MAX_AGE_SECONDS * 1000);

  try {
    const account = await upsertWooAccount(payload);
    await db.ssoLoginNonce.create({ data: { userId: account.userId, nonceHash, expiresAt } });
    return account;
  } catch (error) {
    if (error instanceof Prisma.PrismaClientKnownRequestError && error.code === "P2002") throw new Error("This WooCommerce sign-in link has already been used.");
    throw error;
  }
}
