import { withAuth } from "../../lib/withAuth";
import { logger } from "../../lib/logger";
import { AuthCreditUsageChunk } from "../../controllers/v1/types";
import { queueBillingOperation } from "./batch_billing";
import { autumnService } from "../autumn/autumn.service";
import { toAutumnBillingProperties, type BillingMetadata } from "./types";
import type { Logger } from "winston";

/**
 * If you do not know the subscription_id in the current context, pass subscription_id as undefined.
 */
export async function billTeam(
  team_id: string,
  subscription_id: string | null | undefined,
  credits: number,
  api_key_id: number | null,
  billing: BillingMetadata,
  logger?: Logger,
) {
  return withAuth(
    async (
      team_id: string,
      subscription_id: string | null | undefined,
      credits: number,
      api_key_id: number | null,
      billing: BillingMetadata,
      logger: Logger | undefined,
    ) => {
      const autumnProperties = {
        source: "billTeam",
        ...toAutumnBillingProperties(billing),
        apiKeyId: api_key_id,
      };
      const trackedInRequest = await autumnService.trackCredits({
        teamId: team_id,
        value: credits,
        properties: autumnProperties,
        requestScoped: true,
      });

      const result = await queueBillingOperation(
        team_id,
        subscription_id,
        credits,
        api_key_id,
        billing,
        false,
        trackedInRequest,
      );

      if (!result.success && trackedInRequest) {
        await autumnService.refundCredits({
          teamId: team_id,
          value: credits,
          properties: autumnProperties,
        });
      }

      return result;
    },
    { success: true, message: "No DB, bypassed." },
  )(team_id, subscription_id, credits, api_key_id, billing, logger);
}

type CheckTeamCreditsResponse = {
  success: boolean;
  message: string;
  remainingCredits: number;
  chunk?: AuthCreditUsageChunk;
};

export async function checkTeamCredits(
  chunk: AuthCreditUsageChunk | null,
  team_id: string,
  credits: number,
): Promise<CheckTeamCreditsResponse> {
  return withAuth(supaCheckTeamCredits, {
    success: true,
    message: "No DB, bypassed",
    remainingCredits: Infinity,
  })(chunk, team_id, credits);
}

function evaluateTeamCredits(
  chunk: AuthCreditUsageChunk,
  credits: number,
  isAutoRechargeEnabled: boolean,
) {
  const allowOverages = chunk.price_should_be_graceful && isAutoRechargeEnabled;
  const remainingCredits = allowOverages
    ? chunk.remaining_credits + chunk.price_credits
    : chunk.remaining_credits;
  const creditsWillBeUsed = chunk.adjusted_credits_used + credits;
  const totalPriceCredits = allowOverages
    ? (chunk.total_credits_sum ?? 100000000) + chunk.price_credits
    : (chunk.total_credits_sum ?? 100000000);
  const creditUsagePercentage =
    chunk.adjusted_credits_used / (chunk.total_credits_sum ?? 100000000);

  return {
    allowOverages,
    remainingCredits,
    creditsWillBeUsed,
    totalPriceCredits,
    creditUsagePercentage,
    success: creditsWillBeUsed <= totalPriceCredits,
  };
}

// if team has enough credits for the operation, return true, else return false
async function supaCheckTeamCredits(
  chunk: AuthCreditUsageChunk | null,
  team_id: string,
  credits: number,
): Promise<CheckTeamCreditsResponse> {
  // WARNING: chunk will be null if team_id is preview -- do not perform operations on it under ANY circumstances - mogery
  if (team_id === "preview" || team_id.startsWith("preview_")) {
    return {
      success: true,
      message: "Preview team, no credits used",
      remainingCredits: Infinity,
    };
  } else if (chunk === null) {
    throw new Error("NULL ACUC passed to supaCheckTeamCredits");
  }

  // If bypassCreditChecks flag is set, return success with infinite credits (infinitely graceful)
  if (chunk.flags?.bypassCreditChecks) {
    return {
      success: true,
      message: "Credit checks bypassed",
      remainingCredits: Infinity,
      chunk,
    };
  }

  // Auto-recharge is now handled entirely by Autumn. The legacy ACUC-driven
  // auto-recharge logic below is disabled to avoid double-charging or firing
  // at the wrong threshold.
  //
  // let isAutoRechargeEnabled = false,
  //   autoRechargeThreshold = 1000;
  // const cacheKey = `team_auto_recharge_${team_id}`;
  // let cachedData = await getValue(cacheKey);
  // if (cachedData) {
  //   const parsedData = JSON.parse(cachedData);
  //   isAutoRechargeEnabled = parsedData.auto_recharge;
  //   autoRechargeThreshold = parsedData.auto_recharge_threshold;
  // } else {
  //   const { data, error } = await supabase_rr_service
  //     .from("teams")
  //     .select("auto_recharge, auto_recharge_threshold")
  //     .eq("id", team_id)
  //     .single();
  //
  //   if (data) {
  //     isAutoRechargeEnabled = data.auto_recharge;
  //     autoRechargeThreshold = data.auto_recharge_threshold;
  //     await setValue(cacheKey, JSON.stringify(data), 300);
  //   }
  // }

  const {
    success,
    remainingCredits,
    creditsWillBeUsed,
    totalPriceCredits,
    creditUsagePercentage,
  } = evaluateTeamCredits(chunk, credits, false);

  // if (
  //   config.AUTO_RECHARGE_ENABLED &&
  //   isAutoRechargeEnabled &&
  //   chunk.remaining_credits < autoRechargeThreshold &&
  //   !chunk.is_extract
  // ) {
  //   logger.info("Auto-recharge triggered", {
  //     team_id,
  //     teamId: team_id,
  //     autoRechargeThreshold,
  //     remainingCredits: chunk.remaining_credits,
  //   });
  //
  //   const autoChargeResult = await autoCharge(chunk, autoRechargeThreshold);
  //
  //   if (autoChargeResult && autoChargeResult.success) {
  //     return {
  //       success: true,
  //       message: autoChargeResult.message,
  //       remainingCredits: allowOverages
  //         ? autoChargeResult.remainingCredits + chunk.price_credits
  //         : autoChargeResult.remainingCredits,
  //       chunk: autoChargeResult.chunk,
  //     };
  //   } else if (allowOverages) {
  //     return {
  //       success: true,
  //       message: "Auto-recharge failed, but price should be graceful",
  //       remainingCredits,
  //       chunk,
  //     };
  //   }
  // }

  // Compare the adjusted total credits used with the credits allowed by the plan (and graceful)
  if (!success) {
    logger.warn("Credit check failed - insufficient credits", {
      team_id,
      teamId: team_id,
      creditsRequested: credits,
      is_extract: chunk.is_extract,
      bypassCreditChecks: chunk.flags?.bypassCreditChecks,
      price_should_be_graceful: chunk.price_should_be_graceful,
      price_credits: chunk.price_credits,
      coupon_credits: chunk.coupon_credits,
      total_credits_sum: chunk.total_credits_sum,
      credits_used: chunk.credits_used,
      adjusted_credits_used: chunk.adjusted_credits_used,
      remaining_credits: chunk.remaining_credits,
      sub_current_period_start: chunk.sub_current_period_start,
      sub_current_period_end: chunk.sub_current_period_end,
      computed_remainingCredits: remainingCredits,
      computed_creditsWillBeUsed: creditsWillBeUsed,
      computed_totalPriceCredits: totalPriceCredits,
      creditUsagePercentage,
      sumComponents: chunk.price_credits + chunk.coupon_credits,
    });
    return {
      success: false,
      message:
        "Insufficient credits to perform this request. For more credits, you can upgrade your plan at https://firecrawl.dev/pricing.",
      remainingCredits,
      chunk,
    };
  }

  return {
    success: true,
    message: "Sufficient credits available",
    remainingCredits,
    chunk,
  };
}
