import { Prisma } from "../../prisma/generated/client";
import Stripe from "stripe";

// Initialize Stripe with the secret key from env if available
const stripe = process.env.STRIPE_SECRET_KEY ? new Stripe(process.env.STRIPE_SECRET_KEY, {
  apiVersion: "2026-05-27.dahlia", // Use latest or your specific API version
}) : null;
const ALLOW_MCP_CLAIM_WITHOUT_STRIPE = process.env.ALLOW_MCP_CLAIM_WITHOUT_STRIPE === "true";

function getErrorStatusCode(error: unknown) {
  return typeof error === "object" &&
    error !== null &&
    "statusCode" in error &&
    typeof (error as { statusCode?: unknown }).statusCode === "number"
    ? (error as { statusCode: number }).statusCode
    : 500;
}

export async function authHold(
  tx: Prisma.TransactionClient,
  taskId: string,
  amount: number,
  currency: string,
  wallet: string,
  idempotencyKey: string
) {
  // Check idempotency
  const existing = await tx.ledgerEntry.findUnique({
    where: { idempotency_key: idempotencyKey },
  });
  if (existing) {
    if (existing.response_status === "SUCCESS") return existing;
    throw new Error(`Previous authHold failed for idempotencyKey: ${idempotencyKey}`);
  }

  // Check if we already have a payment intent for this task
  const task = await tx.task.findUnique({ where: { id: taskId } });
  if (!task || !task.stripe_payment_intent_id) {
    if (ALLOW_MCP_CLAIM_WITHOUT_STRIPE) {
      return await tx.ledgerEntry.create({
        data: {
          task_id: taskId,
          phase: "AUTH_HOLD",
          idempotency_key: idempotencyKey,
          stripe_object_id: null,
          response_status: "SKIPPED_NO_STRIPE_INTENT",
          http_status: 200,
        },
      });
    }

    throw new Error("Task does not have a stripe_payment_intent_id. It must be created via Scout checkout first.");
  }

  // In Phase 1 real flow, the Auth Hold is done by the user before the task becomes OPEN.
  // When an AI claims the task, we don't actually create a new PaymentIntent.
  // We just verify the PaymentIntent has enough funds or is capturable.
  
  // To keep it simple, we just record that the claim successfully locked the existing intent
  return await tx.ledgerEntry.create({
    data: {
      task_id: taskId,
      phase: "AUTH_HOLD",
      idempotency_key: idempotencyKey,
      stripe_object_id: task.stripe_payment_intent_id,
      response_status: "SUCCESS",
      http_status: 200,
    },
  });
}

export async function capturePayment(
  tx: Prisma.TransactionClient,
  taskId: string,
  idempotencyKey: string
) {
  const existing = await tx.ledgerEntry.findUnique({
    where: { idempotency_key: idempotencyKey },
  });
  if (existing) {
    if (existing.response_status === "SUCCESS") return existing;
    throw new Error(`Previous capturePayment failed for idempotencyKey: ${idempotencyKey}`);
  }

  const task = await tx.task.findUnique({ where: { id: taskId } });
  if (!task || !task.stripe_payment_intent_id) {
    throw new Error("Cannot capture without a valid stripe_payment_intent_id on the task");
  }

  const claim = await tx.claim.findFirst({
    where: { task_id: taskId, status: "COMPLETED" },
    orderBy: { created_at: "desc" }
  });

  if (!claim) {
    throw new Error("Cannot capture without a COMPLETED claim");
  }

  let capturedIntentId = task.stripe_payment_intent_id;
  if (task.stripe_payment_intent_id === "promo_free_bounty_intent") {
    // Skip real Stripe capture for promo tasks
  } else {
    try {
      if (!stripe) throw new Error("Stripe is not initialized");
      // Perform real Stripe capture
      const capturedIntent = await stripe.paymentIntents.capture(task.stripe_payment_intent_id, undefined, {
        idempotencyKey
      });
      capturedIntentId = capturedIntent.id;
    } catch (error: unknown) {
      // Record failed capture
      await tx.ledgerEntry.create({
        data: {
          task_id: taskId,
          phase: "CAPTURE",
          idempotency_key: idempotencyKey,
          stripe_object_id: task.stripe_payment_intent_id,
          response_status: "FAILED",
          http_status: getErrorStatusCode(error),
        },
      });
      throw error;
    }
  }

  return await tx.ledgerEntry.create({
    data: {
      task_id: taskId,
      phase: "CAPTURE",
      idempotency_key: idempotencyKey,
      stripe_object_id: capturedIntentId,
      response_status: "SUCCESS",
      http_status: 200,
    },
  });
}

export async function releasePayment(
  tx: Prisma.TransactionClient,
  taskId: string,
  idempotencyKey: string
) {
  const existing = await tx.ledgerEntry.findUnique({
    where: { idempotency_key: idempotencyKey },
  });
  if (existing) {
    if (existing.response_status === "SUCCESS") return existing;
    throw new Error(`Previous releasePayment failed for idempotencyKey: ${idempotencyKey}`);
  }

  const task = await tx.task.findUnique({ where: { id: taskId } });
  if (!task || !task.stripe_payment_intent_id) {
    return await tx.ledgerEntry.create({
      data: {
        task_id: taskId,
        phase: "RELEASE",
        idempotency_key: idempotencyKey,
        stripe_object_id: null,
        response_status: "SUCCESS",
        http_status: 200,
      },
    });
  }

  let canceledIntentId = task.stripe_payment_intent_id;
  if (task.stripe_payment_intent_id === "promo_free_bounty_intent") {
    // Skip real Stripe cancel for promo tasks
  } else {
    try {
      if (!stripe) throw new Error("Stripe is not initialized");
      const canceledIntent = await stripe.paymentIntents.cancel(task.stripe_payment_intent_id, undefined, {
        idempotencyKey
      });
      canceledIntentId = canceledIntent.id;
    } catch (error: unknown) {
      await tx.ledgerEntry.create({
        data: {
          task_id: taskId,
          phase: "RELEASE",
          idempotency_key: idempotencyKey,
          stripe_object_id: task.stripe_payment_intent_id,
          response_status: "FAILED",
          http_status: getErrorStatusCode(error),
        },
      });
      throw error;
    }
  }

  return await tx.ledgerEntry.create({
    data: {
      task_id: taskId,
      phase: "RELEASE",
      idempotency_key: idempotencyKey,
      stripe_object_id: canceledIntentId,
      response_status: "SUCCESS",
      http_status: 200,
    },
  });
}

export async function executePayout(
  tx: Prisma.TransactionClient,
  taskId: string,
  developerWallet: string,
  amount: number,
  currency: string,
  idempotencyKey: string
) {
  const existing = await tx.ledgerEntry.findUnique({
    where: { idempotency_key: idempotencyKey },
  });
  if (existing) {
    if (existing.response_status === "SUCCESS") return existing;
    throw new Error(`Previous executePayout failed for idempotencyKey: ${idempotencyKey}`);
  }

  let transferId = `mock_transfer_${taskId}`;

  // If Stripe is configured and wallet looks like a Stripe Connect Account
  if (stripe && developerWallet.startsWith("acct_") && !ALLOW_MCP_CLAIM_WITHOUT_STRIPE) {
    try {
      const transfer = await stripe.transfers.create({
        amount: amount,
        currency: currency.toLowerCase(),
        destination: developerWallet,
        description: `Bounty Payout for Task ${taskId}`,
      }, { idempotencyKey });
      transferId = transfer.id;
    } catch (error: unknown) {
      await tx.ledgerEntry.create({
        data: {
          task_id: taskId,
          phase: "PAYOUT",
          idempotency_key: idempotencyKey,
          stripe_object_id: null,
          response_status: "FAILED",
          http_status: getErrorStatusCode(error),
        },
      });
      throw error;
    }
  }

  return await tx.ledgerEntry.create({
    data: {
      task_id: taskId,
      phase: "PAYOUT",
      idempotency_key: idempotencyKey,
      stripe_object_id: transferId,
      response_status: "SUCCESS",
      http_status: 200,
    },
  });
}
