import { logger } from "../lib/security/logger";
import { PlanTier, SubscriptionStatus } from "@prisma/client";

export interface ActiveSubscriptionItem {
  handle?: string | null;
  description?: string | null;
  price?: {
    __typename?: string;
    active?: boolean;
    currency?: string;
    amount?: number;
  } | null;
}

export interface ActiveSubscriptionResponse {
  shop?: {
    id: string;
    myshopifyDomain: string;
  } | null;
  billingPeriod?: string | null;
  cancelAtEndOfCycle?: boolean | null;
  trialEndsAt?: string | null;
  currentBillingCycle?: {
    startTime?: string;
    endTime?: string;
  } | null;
  items?: ActiveSubscriptionItem[] | null;
  legacySubscriptionId?: string | null;
}

export interface ResolvedSubscriptionState {
  plan: PlanTier;
  status: SubscriptionStatus;
  planHandle: string;
  displayName: string;
  price: number;
  currency: string;
  billingPeriod: string;
  isTrial: boolean;
  trialEndsAt: Date | null;
  cancelAtEndOfCycle: boolean;
  currentBillingCycleStart: Date | null;
  currentBillingCycleEnd: Date | null;
  shopifyShopId: string | null;
  shopifyAppId: string | null;
  rawSubscription: ActiveSubscriptionResponse | null;
  lookupError?: string | null;
}

const ACTIVE_SUBSCRIPTION_QUERY = `#graphql
  query ActiveSubscription($appId: ID!, $shopId: ID!) {
    activeSubscription(appId: $appId, shopId: $shopId) {
      shop {
        id
        myshopifyDomain
      }
      billingPeriod
      cancelAtEndOfCycle
      trialEndsAt
      currentBillingCycle {
        startTime
        endTime
      }
      items {
        handle
        description
        price {
          __typename
          active
          currency
          ... on FlatRatePrice {
            amount
          }
        }
      }
      legacySubscriptionId
    }
  }
`;

/**
 * Normalizes a Shopify GID (e.g. "gid://shopify/Shop/12345" or "12345" -> "gid://shopify/Shop/12345")
 */
export function formatShopifyGid(type: "Shop" | "App" | "AppSubscription" | string, idOrGid: string | number): string {
  const str = String(idOrGid).trim();
  if (str.startsWith("gid://shopify/")) return str;
  // If it's a numeric or clean ID, format as full GID
  const cleanId = str.replace(/[^\d]/g, "");
  return cleanId ? `gid://shopify/${type}/${cleanId}` : `gid://shopify/${type}/${str}`;
}

/**
 * Resolves the store handle from domain (e.g. "my-store.myshopify.com" -> "my-store")
 */
export function getStoreHandle(shopDomain: string): string {
  return shopDomain
    .toLowerCase()
    .trim()
    .replace(/^https?:\/\//, "")
    .replace(/\/.*$/, "")
    .replace(/\.myshopify\.com$/, "");
}

import { getAppHandleSync } from "./platform-settings.server";

/**
 * Resolves the app handle configured for the Shopify App.
 */
export function getAppHandle(): string {
  return getAppHandleSync();
}


/**
 * Builds the official Shopify-hosted plan selection / charges URL.
 * Pattern: https://admin.shopify.com/store/:store_handle/charges/:app_handle/pricing_plans
 */
export function getShopifyPricingPlansUrl(shopDomain: string, appHandle?: string): string {
  const storeHandle = getStoreHandle(shopDomain);
  const handle = appHandle || getAppHandle();
  return `https://admin.shopify.com/store/${storeHandle}/apps/${handle}/billing`;
}

/**
 * Builds the official Shopify embedded app URL.
 * Pattern: https://admin.shopify.com/store/:store_handle/apps/:app_handle
 */
export function getShopifyEmbeddedAppUrl(shopDomain: string, appHandle?: string): string {
  const storeHandle = getStoreHandle(shopDomain);
  const handle = appHandle || getAppHandle();
  return `https://admin.shopify.com/store/${storeHandle}/apps/${handle}`;
}

/**
 * Fetches the active subscription for a shop from the Shopify Partner API.
 */
export async function queryPartnerActiveSubscription({
  shopId,
  appId,
  partnerAccessToken,
  organizationId,
}: {
  shopId: string;
  appId?: string;
  partnerAccessToken?: string;
  organizationId?: string;
}): Promise<{ data?: { activeSubscription: ActiveSubscriptionResponse | null }; error?: string }> {
  const token = partnerAccessToken || process.env.SHOPIFY_PARTNER_API_TOKEN || process.env.SHOPIFY_PARTNER_ACCESS_TOKEN || process.env.PARTNER_ACCESS_TOKEN;
  const orgId = organizationId || process.env.SHOPIFY_PARTNER_ORGANIZATION_ID || process.env.PARTNER_ORGANIZATION_ID;
  const targetAppId = appId || process.env.SHOPIFY_APP_ID || process.env.SHOPIFY_APP_GID || "gid://shopify/App/1";

  if (!token) {
    logger.warn("Shopify Partner API token is not configured (SHOPIFY_PARTNER_API_TOKEN)");
    return { error: "PARTNER_API_TOKEN_MISSING" };
  }

  const endpoint = orgId
    ? `https://partners.shopify.com/${orgId}/api/2026-07/graphql.json`
    : `https://partners.shopify.com/api/2026-07/graphql.json`;

  const formattedAppId = formatShopifyGid("App", targetAppId);
  const formattedShopId = formatShopifyGid("Shop", shopId);

  try {
    const response = await fetch(endpoint, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "X-Shopify-Access-Token": token,
      },
      body: JSON.stringify({
        query: ACTIVE_SUBSCRIPTION_QUERY,
        variables: {
          appId: formattedAppId,
          shopId: formattedShopId,
        },
      }),
    });

    if (!response.ok) {
      const errText = await response.text();
      logger.error("Partner API HTTP error", { status: response.status, body: errText });
      return { error: `HTTP_${response.status}` };
    }

    const json = await response.json();
    if (json.errors && json.errors.length > 0) {
      logger.error("Partner API GraphQL errors", { errors: json.errors });
      return { error: json.errors[0]?.message || "PARTNER_GRAPHQL_ERROR" };
    }

    return { data: json.data };
  } catch (err: any) {
    logger.error("Partner API network error", err);
    return { error: err.message || "NETWORK_ERROR" };
  }
}

/**
 * Maps an ActiveSubscription response to internal plan tier and subscription metadata.
 */
export function mapActiveSubscriptionToPlan(
  activeSub: ActiveSubscriptionResponse | null | undefined,
  shopIdGid?: string | null
): ResolvedSubscriptionState {
  // Default FREE tier configuration
  if (!activeSub || !activeSub.items || activeSub.items.length === 0) {
    return {
      plan: "FREE",
      status: "ACTIVE",
      planHandle: "free",
      displayName: "Free",
      price: 0,
      currency: "USD",
      billingPeriod: "EVERY_30_DAYS",
      isTrial: false,
      trialEndsAt: null,
      cancelAtEndOfCycle: false,
      currentBillingCycleStart: null,
      currentBillingCycleEnd: null,
      shopifyShopId: activeSub?.shop?.id || shopIdGid || null,
      shopifyAppId: null,
      rawSubscription: activeSub || null,
    };
  }

  const firstItem = activeSub.items[0];
  const itemHandle = (firstItem.handle || "").toLowerCase().trim();
  const itemDescription = (firstItem.description || "").toLowerCase();
  const priceAmount = firstItem.price?.amount !== undefined ? Number(firstItem.price.amount) : 0;
  const currency = firstItem.price?.currency || "USD";

  // Resolve Plan Tier using item handle as primary identifier, falling back to price
  let plan: PlanTier = "FREE";
  let displayName = "Free";
  let price = 0;
  let planHandle = "free";

  if (itemHandle.includes("pro") || itemDescription.includes("pro") || priceAmount >= 79) {
    plan = "PRO";
    displayName = "Pro";
    price = 79;
    planHandle = itemHandle || "pro";
  } else if (itemHandle.includes("starter") || itemDescription.includes("starter") || priceAmount >= 29) {
    plan = "STARTER";
    displayName = "Starter";
    price = 29;
    planHandle = itemHandle || "starter";
  } else {
    plan = "FREE";
    displayName = "Free";
    price = 0;
    planHandle = itemHandle || "free";
  }

  const now = new Date();
  const trialEndsAtDate = activeSub.trialEndsAt ? new Date(activeSub.trialEndsAt) : null;
  const isTrial = Boolean(trialEndsAtDate && trialEndsAtDate > now);

  const cancelAtEndOfCycle = Boolean(activeSub.cancelAtEndOfCycle);
  const cycleStart = activeSub.currentBillingCycle?.startTime ? new Date(activeSub.currentBillingCycle.startTime) : null;
  const cycleEnd = activeSub.currentBillingCycle?.endTime ? new Date(activeSub.currentBillingCycle.endTime) : null;

  // Determine Subscription Status
  let status: SubscriptionStatus = "ACTIVE";
  if (isTrial) {
    status = "ACTIVE"; // Merchant has active access during trial
  } else if (cancelAtEndOfCycle) {
    status = "CANCELLED"; // Scheduled to cancel at cycle end, access remains until cycleEnd
  }

  return {
    plan,
    status,
    planHandle,
    displayName,
    price,
    currency,
    billingPeriod: activeSub.billingPeriod || "EVERY_30_DAYS",
    isTrial,
    trialEndsAt: trialEndsAtDate,
    cancelAtEndOfCycle,
    currentBillingCycleStart: cycleStart,
    currentBillingCycleEnd: cycleEnd,
    shopifyShopId: activeSub.shop?.id || shopIdGid || null,
    shopifyAppId: null,
    rawSubscription: activeSub,
  };
}
