"use server";

import { revalidatePath } from "next/cache";
import { redirect } from "next/navigation";
import { ID, Permission, Query, Role } from "node-appwrite";

import { logAudit } from "./audit";
import { persistCardFromMockCheckout } from "./saved-card-actions";
import { getDefaultCard } from "./saved-card-queries";
import { DATABASE_ID, TABLES, type SubscriptionPayment, type TenantPlan } from "./schema";
import { createAdminClient } from "./server";
import { requireRole, requireTenant } from "./tenant-guard";
import { PLAN_CATALOG } from "./subscription-types";
import { getShopierPlanUrl, isShopierEnabled } from "../payments/shopier";
import { createPolarCheckout, isPolarEnabled } from "../payments/polar";

const PRO_VALIDITY_DAYS = 30;

function teamRowPermissions(tenantId: string) {
  return [
    Permission.read(Role.team(tenantId, "owner")),
    Permission.read(Role.team(tenantId, "admin")),
    Permission.update(Role.team(tenantId, "owner")),
    Permission.delete(Role.team(tenantId, "owner")),
  ];
}

function generateOrderId(): string {
  const t = Date.now().toString(36);
  const r = Math.random().toString(36).slice(2, 10);
  return `ord_${t}_${r}`;
}

export async function startMockCheckoutAction(formData: FormData): Promise<void> {
  const plan = String(formData.get("plan") ?? "") as TenantPlan;
  if (plan !== "pro") throw new Error("Geçersiz plan.");

  const ctx = await requireTenant();
  requireRole(ctx, ["owner"]);

  const catalog = PLAN_CATALOG[plan];
  const orderId = generateOrderId();

  const { tablesDB } = createAdminClient();
  await tablesDB.createRow(
    DATABASE_ID,
    TABLES.subscriptionPayments,
    ID.unique(),
    {
      tenantId: ctx.tenantId,
      createdBy: ctx.user.id,
      orderId,
      plan,
      amount: catalog.price,
      currency: catalog.currency,
      status: "pending",
      provider: "mock",
    },
    teamRowPermissions(ctx.tenantId),
  );

  await logAudit({
    tenantId: ctx.tenantId,
    userId: ctx.user.id,
    action: "create",
    entityType: "subscription_payment",
    entityId: orderId,
    changes: { plan, amount: catalog.price, provider: "mock" },
  });

  redirect(`/settings/billing/checkout/${orderId}`);
}

async function findPendingPaymentByOrderId(
  tenantId: string,
  orderId: string,
): Promise<SubscriptionPayment | null> {
  const { tablesDB } = createAdminClient();
  const result = await tablesDB.listRows({
    databaseId: DATABASE_ID,
    tableId: TABLES.subscriptionPayments,
    queries: [Query.equal("orderId", orderId), Query.equal("tenantId", tenantId), Query.limit(1)],
  });
  return (result.rows[0] as unknown as SubscriptionPayment) ?? null;
}

export async function confirmMockPaymentAction(formData: FormData): Promise<void> {
  const orderId = String(formData.get("orderId") ?? "");
  if (!orderId) throw new Error("orderId eksik.");

  const ctx = await requireTenant();
  requireRole(ctx, ["owner"]);

  const payment = await findPendingPaymentByOrderId(ctx.tenantId, orderId);
  if (!payment) throw new Error("Ödeme bulunamadı.");
  if (payment.status === "success") {
    redirect(`/settings/billing?upgraded=1`);
  }
  if (payment.provider !== "mock") {
    throw new Error("Bu ödeme mock olarak onaylanamaz.");
  }

  const saveCard = String(formData.get("saveCard") ?? "") === "true";
  const useSavedCardId = String(formData.get("savedCardId") ?? "");

  const { tablesDB } = createAdminClient();
  const now = new Date();
  const expires = new Date(now.getTime() + PRO_VALIDITY_DAYS * 24 * 60 * 60 * 1000);

  await tablesDB.updateRow(DATABASE_ID, TABLES.subscriptionPayments, payment.$id, {
    status: "success",
    processedAt: now.toISOString(),
    providerPayload: JSON.stringify({
      mock: true,
      confirmedBy: ctx.user.id,
      usedSavedCardId: useSavedCardId || undefined,
    }),
  });

  if (ctx.settings) {
    await tablesDB.updateRow(DATABASE_ID, TABLES.tenantSettings, ctx.settings.$id, {
      plan: payment.plan,
      planStartedAt: now.toISOString(),
      planExpiresAt: expires.toISOString(),
      lastPaymentId: payment.$id,
    });
  }

  if (saveCard && !useSavedCardId) {
    const last4 = String(formData.get("cardLast4") ?? "").replace(/\D/g, "").slice(-4);
    const month = parseInt(String(formData.get("cardExpiryMonth") ?? "0"), 10);
    const year = parseInt(String(formData.get("cardExpiryYear") ?? "0"), 10);
    const brand = String(formData.get("cardBrand") ?? "unknown");
    const holder = String(formData.get("cardHolder") ?? "").trim();

    if (last4.length === 4 && month > 0 && year >= 2026) {
      const existingDefault = await getDefaultCard(ctx.tenantId);
      try {
        await persistCardFromMockCheckout({
          brand,
          last4,
          expiryMonth: month,
          expiryYear: year,
          holderName: holder,
          makeDefault: !existingDefault,
        });
      } catch {
        // best-effort — payment already succeeded, don't fail upgrade if card save errors
      }
    }
  }

  await logAudit({
    tenantId: ctx.tenantId,
    userId: ctx.user.id,
    action: "update",
    entityType: "subscription_payment",
    entityId: payment.$id,
    changes: { status: "success", plan: payment.plan, expires: expires.toISOString() },
  });

  revalidatePath("/settings/billing");
  redirect(`/settings/billing?upgraded=1`);
}

export async function cancelMockPaymentAction(formData: FormData): Promise<void> {
  const orderId = String(formData.get("orderId") ?? "");
  if (!orderId) throw new Error("orderId eksik.");

  const ctx = await requireTenant();
  requireRole(ctx, ["owner"]);

  const payment = await findPendingPaymentByOrderId(ctx.tenantId, orderId);
  if (!payment) {
    redirect(`/settings/billing`);
  }
  if (payment && payment.status === "pending") {
    const { tablesDB } = createAdminClient();
    await tablesDB.updateRow(DATABASE_ID, TABLES.subscriptionPayments, payment.$id, {
      status: "failed",
      processedAt: new Date().toISOString(),
      providerPayload: JSON.stringify({ mock: true, cancelledBy: ctx.user.id }),
    });

    await logAudit({
      tenantId: ctx.tenantId,
      userId: ctx.user.id,
      action: "update",
      entityType: "subscription_payment",
      entityId: payment.$id,
      changes: { status: "failed" },
    });
  }

  revalidatePath("/settings/billing");
  redirect(`/settings/billing?cancelled=1`);
}

export async function downgradeToFreeAction(): Promise<void> {
  const ctx = await requireTenant();
  requireRole(ctx, ["owner"]);

  if (!ctx.settings) throw new Error("Ayar yok.");

  const { tablesDB } = createAdminClient();
  await tablesDB.updateRow(DATABASE_ID, TABLES.tenantSettings, ctx.settings.$id, {
    plan: "free",
    planExpiresAt: null,
  });

  await logAudit({
    tenantId: ctx.tenantId,
    userId: ctx.user.id,
    action: "update",
    entityType: "tenant_settings",
    entityId: ctx.settings.$id,
    changes: { plan: "free" },
  });

  revalidatePath("/settings/billing");
  redirect(`/settings/billing?downgraded=1`);
}

export async function startShopierCheckoutAction(formData: FormData): Promise<void> {
  const plan = String(formData.get("plan") ?? "") as TenantPlan;
  if (plan !== "pro") throw new Error("Geçersiz plan.");

  const ctx = await requireTenant();
  requireRole(ctx, ["owner"]);

  const storeUrl = getShopierPlanUrl(plan);
  if (!storeUrl) throw new Error("Shopier mağaza URL'i ayarlanmamış.");

  const catalog = PLAN_CATALOG[plan];
  const orderId = generateOrderId();

  const { tablesDB } = createAdminClient();
  await tablesDB.createRow(
    DATABASE_ID,
    TABLES.subscriptionPayments,
    ID.unique(),
    {
      tenantId: ctx.tenantId,
      createdBy: ctx.user.id,
      orderId,
      plan,
      amount: catalog.price,
      currency: catalog.currency,
      status: "pending",
      provider: "shopier",
      // Webhook'ta tenant eşleştirmek için alıcı emailini sakla
      providerPayload: JSON.stringify({ userEmail: ctx.user.email }),
    },
    teamRowPermissions(ctx.tenantId),
  );

  await logAudit({
    tenantId: ctx.tenantId,
    userId: ctx.user.id,
    action: "create",
    entityType: "subscription_payment",
    entityId: orderId,
    changes: { plan, amount: catalog.price, provider: "shopier" },
  });

  // Kullanıcıyı doğrudan Shopier mağaza ürün sayfasına yönlendir
  redirect(storeUrl);
}

export async function startPolarCheckoutAction(formData: FormData): Promise<void> {
  const plan = String(formData.get("plan") ?? "") as TenantPlan;
  if (plan !== "pro") throw new Error("Geçersiz plan.");

  const ctx = await requireTenant();
  requireRole(ctx, ["owner"]);

  const catalog = PLAN_CATALOG[plan];
  const orderId = generateOrderId();
  const appUrl = process.env.APP_URL?.replace(/\/$/, "") ?? "http://localhost:3000";

  const { tablesDB } = createAdminClient();
  await tablesDB.createRow(
    DATABASE_ID,
    TABLES.subscriptionPayments,
    ID.unique(),
    {
      tenantId: ctx.tenantId,
      createdBy: ctx.user.id,
      orderId,
      plan,
      amount: catalog.price,
      currency: catalog.currency,
      status: "pending",
      provider: "polar",
    },
    teamRowPermissions(ctx.tenantId),
  );

  await logAudit({
    tenantId: ctx.tenantId,
    userId: ctx.user.id,
    action: "create",
    entityType: "subscription_payment",
    entityId: orderId,
    changes: { plan, amount: catalog.price, provider: "polar" },
  });

  const checkout = await createPolarCheckout({
    orderId,
    tenantId: ctx.tenantId,
    userEmail: ctx.user.email,
    successUrl: `${appUrl}/settings/billing?upgraded=1`,
  });

  redirect(checkout.url);
}

// Unified entry point — PAYMENT_PROVIDER env ile yönlendirir.
export async function startCheckoutAction(formData: FormData): Promise<void> {
  if (isPolarEnabled()) return startPolarCheckoutAction(formData);
  if (isShopierEnabled()) return startShopierCheckoutAction(formData);
  return startMockCheckoutAction(formData);
}
