import { loadSettings, setSetting } from "../config/settings";
import type { PremiumState, PremiumStatus } from "../../shared/types";
import { createLogger } from "../../shared/logger";
import { isAirGapped } from "../config/air-gapped";
import {
  errorResult,
  getErrorMessage,
  okResult,
  type Result,
} from "../../shared/result";

const logger = createLogger("Premium");

/**
 * Vessel Premium subscription manager.
 *
 * Architecture:
 * - Stripe Checkout handles payment (hosted by Stripe)
 * - A lightweight verification API (Cloudflare Worker) validates subscriptions
 * - Vessel caches the subscription status locally and re-validates periodically
 * - 7-day offline grace period: if we can't reach the verification API,
 *   an active subscription remains valid for 7 days from last validation
 */

// The verification API URL — points to your Cloudflare Worker
const VERIFICATION_API =
  process.env.VESSEL_PREMIUM_API || "https://vesselpremium.quantaintellect.com";

const FREE_TOOL_ITERATION_LIMIT = 50;
const REVALIDATION_INTERVAL_MS = 24 * 60 * 60 * 1000; // 24 hours
const OFFLINE_GRACE_PERIOD_MS = 7 * 24 * 60 * 60 * 1000; // 7 days
const MAX_API_ERROR_LOG_LENGTH = 300;

type PremiumVerificationResponse = {
  status: PremiumStatus;
  customerId: string;
  verificationToken: string;
  email: string;
  expiresAt: string;
};

type ActivationCodeStartResult = Result<{
  email: string;
  challengeToken: string;
}>;

type ActivationCodeVerifyResult = Result<
  { state: PremiumState },
  { state: PremiumState }
>;

async function readApiErrorDetail(res: Response): Promise<string> {
  try {
    const text = (await res.text()).trim();
    if (!text) return "";

    try {
      const data = JSON.parse(text) as { error?: unknown; message?: unknown };
      const detail = data.error || data.message;
      if (typeof detail === "string" && detail.trim()) {
        return detail.trim().slice(0, MAX_API_ERROR_LOG_LENGTH);
      }
    } catch {
      // Fall back to logging the raw body below.
    }

    return text.slice(0, MAX_API_ERROR_LOG_LENGTH);
  } catch {
    return "";
  }
}

// --- Premium feature definitions ---

/** Tools that require a premium subscription */
export const PREMIUM_TOOLS = new Set([
  "screenshot",
  "save_session",
  "load_session",
  "list_sessions",
  "delete_session",
  "flow_start",
  "flow_advance",
  "flow_status",
  "flow_end",
  "metrics",
  "extract_table",
  "vault_login",
  "vault_status",
  "vault_totp",
  "human_vault_list",
  "human_vault_fill",
  "human_vault_remove",
  "research_confirm_brief",
  "research_approve_objectives",
  "research_export_report",
]);

/** Features gated behind premium (checked by name in UI/IPC) */
export const PREMIUM_FEATURES = new Set([
  "obsidian",
  "devtools",
  "unlimited_iterations",
  "vault",
  "human_vault",
  "automation_kits",
  "research",
]);

// --- Status checks ---

export function isPremium(): boolean {
  const { premium } = loadSettings();
  if (premium.status !== "active" && premium.status !== "trialing") {
    return false;
  }

  // Legacy installs may have an active cached state from before validation
  // timestamps were persisted. Trust that state until the next verification.
  if (!premium.validatedAt) {
    return true;
  }

  const lastValidated = new Date(premium.validatedAt).getTime();
  if (!Number.isFinite(lastValidated)) {
    return false;
  }
  return Date.now() - lastValidated < OFFLINE_GRACE_PERIOD_MS;
}

export function getPremiumState(): PremiumState {
  return { ...loadSettings().premium };
}

export function getEffectiveMaxIterations(): number {
  if (isPremium()) {
    return loadSettings().maxToolIterations || 200;
  }
  return FREE_TOOL_ITERATION_LIMIT;
}

export function resetPremium(): PremiumState {
  const fresh: PremiumState = {
    status: "free",
    customerId: "",
    verificationToken: "",
    email: "",
    validatedAt: "",
    expiresAt: "",
  };
  setSetting("premium", fresh);
  return fresh;
}

export function isToolGated(toolName: string): boolean {
  return PREMIUM_TOOLS.has(toolName) && !isPremium();
}

export function isFeatureGated(featureName: string): boolean {
  return PREMIUM_FEATURES.has(featureName) && !isPremium();
}

export function getPremiumToolGateMessage(toolName: string): string {
  return `This tool (${toolName}) requires Vessel Premium. Upgrade at Settings > Premium to unlock screenshot, session management, workflow tracking, and more.`;
}

export function assertToolUnlocked(toolName: string): void {
  if (isToolGated(toolName)) {
    throw new Error(getPremiumToolGateMessage(toolName));
  }
}

export function assertFeatureUnlocked(
  featureName: string,
  featureLabel = featureName,
): void {
  if (isFeatureGated(featureName)) {
    throw new Error(`${featureLabel} requires Vessel Premium.`);
  }
}

// --- Stripe Checkout ---

/**
 * Open a Stripe Checkout session in the user's default browser.
 * The verification API creates the checkout session and returns the URL.
 */
export async function getCheckoutUrl(
  email?: string,
): Promise<Result<{ url: string }>> {
  if (isAirGapped()) {
    return errorResult("Checkout is unavailable in air-gapped mode.");
  }
  try {
    const params = new URLSearchParams();
    if (email) params.set("email", email);

    const res = await fetch(`${VERIFICATION_API}/checkout?${params}`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
    });

    if (!res.ok) {
      const body = await res.text();
      return errorResult(body || `HTTP ${res.status}`);
    }

    const { url } = (await res.json()) as { url: string };
    return okResult({ url });
  } catch (err) {
    return errorResult(getErrorMessage(err, "Failed to create checkout"));
  }
}

/**
 * Open the Stripe Customer Portal for subscription management.
 */
export async function getPortalUrl(): Promise<Result<{ url: string }>> {
  if (isAirGapped()) {
    return errorResult("Billing portal is unavailable in air-gapped mode.");
  }
  const current = loadSettings().premium;
  const identifier = current.verificationToken;

  if (!identifier) {
    return errorResult(
      "Verify your Premium subscription before opening billing management.",
    );
  }

  try {
    const res = await fetch(`${VERIFICATION_API}/portal`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ identifier }),
    });

    if (!res.ok) {
      const detail = await readApiErrorDetail(res);
      return errorResult(detail || `HTTP ${res.status}`);
    }

    const { url } = (await res.json()) as { url?: unknown };
    if (typeof url !== "string" || !url.trim()) {
      return errorResult("Billing portal did not return a valid URL.");
    }
    return okResult({ url });
  } catch (err) {
    return errorResult(getErrorMessage(err, "Failed to open billing portal"));
  }
}

// --- Subscription verification ---

/**
 * Verify subscription status against the verification API.
 * Called on app launch and periodically in the background.
 */
export async function verifySubscription(
  identifier?: string,
): Promise<PremiumState> {
  if (isAirGapped()) {
    return loadSettings().premium;
  }

  const current = loadSettings().premium;
  const verificationIdentifier =
    identifier || current.verificationToken || current.customerId;

  if (!verificationIdentifier) {
    return current;
  }

  try {
    const res = await fetch(`${VERIFICATION_API}/verify`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ identifier: verificationIdentifier }),
    });

    if (!res.ok) {
      // Can't reach API — keep current state (offline grace handles expiry)
      const detail = await readApiErrorDetail(res);
      logger.warn(
        "Verification API returned a non-OK status:",
        res.status,
        detail,
      );
      return current;
    }

    const data = (await res.json()) as PremiumVerificationResponse;

    const updated: PremiumState = {
      status: data.status,
      customerId: data.customerId || current.customerId,
      verificationToken: data.verificationToken || verificationIdentifier,
      email: data.email || current.email,
      validatedAt: new Date().toISOString(),
      expiresAt: data.expiresAt,
    };

    setSetting("premium", updated);
    return updated;
  } catch (err) {
    logger.warn("Verification failed:", err);
    return current;
  }
}

/**
 * Request a short-lived activation code for the subscription email.
 */
export async function requestActivationCode(
  email: string,
): Promise<ActivationCodeStartResult> {
  if (isAirGapped()) {
    return errorResult("Activation codes are unavailable in air-gapped mode.");
  }

  const normalizedEmail = email.trim().toLowerCase();
  if (!normalizedEmail) {
    return errorResult("Email is required");
  }

  try {
    const res = await fetch(`${VERIFICATION_API}/activate/start`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ email: normalizedEmail }),
    });

    const data = (await res.json().catch(() => ({}))) as {
      challengeToken?: string;
      error?: string;
    };
    if (!res.ok || !data.challengeToken) {
      return errorResult(data.error || `HTTP ${res.status}`);
    }

    return okResult({
      email: normalizedEmail,
      challengeToken: data.challengeToken,
    });
  } catch (err) {
    return errorResult(getErrorMessage(err, "Failed to send code"));
  }
}

/**
 * Verify an emailed activation code and persist the verified premium token.
 */
export async function verifyActivationCode(
  email: string,
  code: string,
  challengeToken: string,
): Promise<ActivationCodeVerifyResult> {
  if (isAirGapped()) {
    return errorResult("Activation codes are unavailable in air-gapped mode.", {
      state: getPremiumState(),
    });
  }

  const normalizedEmail = email.trim().toLowerCase();
  const trimmedCode = code.trim();
  if (!normalizedEmail) {
    return errorResult("Email is required", { state: getPremiumState() });
  }
  if (!trimmedCode) {
    return errorResult("Code is required", { state: getPremiumState() });
  }
  if (!challengeToken.trim()) {
    return errorResult("Request a new activation code and try again.", {
      state: getPremiumState(),
    });
  }

  try {
    const res = await fetch(`${VERIFICATION_API}/activate/verify`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        email: normalizedEmail,
        code: trimmedCode,
        challengeToken: challengeToken.trim(),
      }),
    });

    const data = (await res.json().catch(() => ({}))) as Partial<PremiumVerificationResponse> & {
      error?: string;
    };
    if (!res.ok) {
      return errorResult(data.error || `HTTP ${res.status}`, {
        state: getPremiumState(),
      });
    }

    const updated: PremiumState = {
      status: data.status ?? "free",
      customerId: data.customerId || "",
      verificationToken: data.verificationToken || "",
      email: data.email || normalizedEmail,
      validatedAt: new Date().toISOString(),
      expiresAt: data.expiresAt || "",
    };

    setSetting("premium", updated);
    return isPremiumActiveState(updated)
      ? okResult({ state: updated })
      : errorResult("Subscription is not active.", { state: updated });
  } catch (err) {
    return errorResult(getErrorMessage(err, "Failed to verify code"), {
      state: getPremiumState(),
    });
  }
}

// --- Background revalidation ---

let revalidationTimer: ReturnType<typeof setInterval> | null = null;

export function startBackgroundRevalidation(): void {
  if (revalidationTimer) return;
  if (isAirGapped()) return;

  // Check on startup if we need to revalidate
  const { premium } = loadSettings();
  const identifier = premium.verificationToken || premium.customerId;
  if (identifier) {
    const lastValidated = premium.validatedAt
      ? new Date(premium.validatedAt).getTime()
      : 0;
    if (Date.now() - lastValidated > REVALIDATION_INTERVAL_MS) {
      void verifySubscription(identifier);
    }
  }

  // Then check every 24 hours
  revalidationTimer = setInterval(() => {
    const { premium: p } = loadSettings();
    const currentIdentifier = p.verificationToken || p.customerId;
    if (currentIdentifier) {
      void verifySubscription(currentIdentifier);
    }
  }, REVALIDATION_INTERVAL_MS);
}

export function stopBackgroundRevalidation(): void {
  clearInterval(revalidationTimer);
  revalidationTimer = null;
}

export function isPremiumActiveState(state: PremiumState): boolean {
  return state.status === "active" || state.status === "trialing";
}
