import { createSign } from 'crypto';
import { NormalizedStorePurchase, VerifyPurchaseInput } from './billing.types';
import { isCreditProduct, isKnownBillingProduct, isSubscriptionProduct } from './billingProducts';

const GOOGLE_TOKEN_URL = 'https://oauth2.googleapis.com/token';
const GOOGLE_ANDROID_PUBLISHER_SCOPE = 'https://www.googleapis.com/auth/androidpublisher';
const GOOGLE_ANDROID_PUBLISHER_BASE = 'https://androidpublisher.googleapis.com/androidpublisher/v3';

function base64UrlEncode(input: Buffer | string): string {
  const value = Buffer.isBuffer(input) ? input.toString('base64') : Buffer.from(input).toString('base64');
  return value.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, '');
}

function readGoogleServiceAccount(): { client_email: string; private_key: string } {
  const raw = String(process.env.GOOGLE_PLAY_SERVICE_ACCOUNT_JSON || '').trim();
  if (!raw) {
    throw new Error('GOOGLE_PLAY_SERVICE_ACCOUNT_JSON is not configured');
  }

  let parsed: any;
  try {
    parsed = raw.startsWith('{') ? JSON.parse(raw) : JSON.parse(Buffer.from(raw, 'base64').toString('utf8'));
  } catch {
    throw new Error('Invalid GOOGLE_PLAY_SERVICE_ACCOUNT_JSON value');
  }

  const clientEmail = String(parsed?.client_email || '').trim();
  const privateKey = String(parsed?.private_key || '').trim();
  if (!clientEmail || !privateKey) {
    throw new Error('Google service account is missing client_email/private_key');
  }

  return { client_email: clientEmail, private_key: privateKey };
}

function createGoogleAssertionJwt(clientEmail: string, privateKey: string): string {
  const now = Math.floor(Date.now() / 1000);
  const header = { alg: 'RS256', typ: 'JWT' };
  const payload = {
    iss: clientEmail,
    scope: GOOGLE_ANDROID_PUBLISHER_SCOPE,
    aud: GOOGLE_TOKEN_URL,
    iat: now,
    exp: now + 60 * 60,
  };

  const encodedHeader = base64UrlEncode(JSON.stringify(header));
  const encodedPayload = base64UrlEncode(JSON.stringify(payload));
  const unsigned = `${encodedHeader}.${encodedPayload}`;

  const signer = createSign('RSA-SHA256');
  signer.update(unsigned);
  signer.end();
  const signature = signer.sign(privateKey);

  return `${unsigned}.${base64UrlEncode(signature)}`;
}

async function getGoogleAccessToken(): Promise<string> {
  const account = readGoogleServiceAccount();
  const assertion = createGoogleAssertionJwt(account.client_email, account.private_key);

  const body = new URLSearchParams({
    grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
    assertion,
  });

  const response = await fetch(GOOGLE_TOKEN_URL, {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: body.toString(),
  });

  if (!response.ok) {
    const text = await response.text();
    throw new Error(`Failed to get Google access token: ${response.status} ${text}`);
  }

  const data = (await response.json()) as { access_token?: string };
  const accessToken = String(data?.access_token || '').trim();
  if (!accessToken) {
    throw new Error('Google access token is missing');
  }

  return accessToken;
}

function resolveGooglePackageName(payload: Record<string, any>): string {
  return String(process.env.GOOGLE_PLAY_PACKAGE_NAME || '').trim() || String(payload?.packageName || '').trim();
}

function parseMsToDate(input: unknown): Date | undefined {
  const n = Number(input);
  if (!Number.isFinite(n) || n <= 0) return undefined;
  return new Date(n);
}

export async function verifyGooglePurchase(input: VerifyPurchaseInput): Promise<NormalizedStorePurchase> {
  if (!isKnownBillingProduct(input.productId)) {
    throw new Error('Unknown Google product id');
  }
  const isCreditPack = isCreditProduct(input.productId);
  const isSubscription = isSubscriptionProduct(input.productId);

  const payload = (input.payload || {}) as Record<string, any>;
  const purchaseToken = String(input.purchaseToken || payload.purchaseToken || payload.token || '').trim();
  if (!purchaseToken) {
    throw new Error('Missing Google purchase token');
  }

  const packageName = resolveGooglePackageName(payload);
  if (!packageName) {
    throw new Error('GOOGLE_PLAY_PACKAGE_NAME is required for verification');
  }

  const accessToken = await getGoogleAccessToken();

  let apiResponse: any = null;
  if (isSubscription) {
    const url = `${GOOGLE_ANDROID_PUBLISHER_BASE}/applications/${encodeURIComponent(packageName)}/purchases/subscriptionsv2/tokens/${encodeURIComponent(purchaseToken)}`;
    const response = await fetch(url, {
      method: 'GET',
      headers: { Authorization: `Bearer ${accessToken}` },
    });
    if (!response.ok) {
      const text = await response.text();
      throw new Error(`Google subscription verification failed: ${response.status} ${text}`);
    }
    apiResponse = await response.json();
  } else {
    const url = `${GOOGLE_ANDROID_PUBLISHER_BASE}/applications/${encodeURIComponent(packageName)}/purchases/productsv2/tokens/${encodeURIComponent(purchaseToken)}`;
    const response = await fetch(url, {
      method: 'GET',
      headers: { Authorization: `Bearer ${accessToken}` },
    });
    if (!response.ok) {
      const text = await response.text();
      throw new Error(`Google one-time verification failed: ${response.status} ${text}`);
    }
    apiResponse = await response.json();
  }

  const lineItems = Array.isArray(apiResponse?.lineItems) ? apiResponse.lineItems : [];
  const firstLineItem = lineItems[0] || {};
  const resolvedProductId = String(
    firstLineItem?.productId || apiResponse?.productId || apiResponse?.product_id || input.productId || '',
  ).trim();

  if (!resolvedProductId || resolvedProductId !== input.productId) {
    throw new Error('Google product mismatch during verification');
  }

  const transactionId = String(
    apiResponse?.latestOrderId || apiResponse?.orderId || input.transactionId || payload.transactionId || purchaseToken,
  ).trim();
  const originalTransactionId = String(
    apiResponse?.linkedPurchaseToken || input.originalTransactionId || purchaseToken || transactionId,
  ).trim();

  const expiryFromLineItem = parseMsToDate(firstLineItem?.expiryTime) || parseMsToDate(firstLineItem?.expiryTimeMillis);
  const expiryFromPayload = parseMsToDate(payload?.expiryTimeMillis);
  const expiresAt = isSubscription ? expiryFromLineItem || expiryFromPayload : undefined;

  const subscriptionState = String(apiResponse?.subscriptionState || '').toUpperCase();
  const nowMs = Date.now();
  let status: 'active' | 'expired' | 'cancelled' | 'revoked' = 'active';
  if (isSubscription) {
    if (subscriptionState.includes('CANCELED')) status = 'cancelled';
    else if (subscriptionState.includes('EXPIRED')) status = 'expired';
    else if (subscriptionState.includes('ON_HOLD') || subscriptionState.includes('PAUSED')) status = 'expired';
    else status = expiresAt && expiresAt.getTime() > nowMs ? 'active' : 'expired';
  }

  if (!isSubscription && isCreditPack) {
    const purchaseState = String(apiResponse?.purchaseStateContext?.purchaseState || '').toUpperCase();
    if (purchaseState && purchaseState !== 'PURCHASED') {
      throw new Error(`Google one-time purchase is not in PURCHASED state: ${purchaseState}`);
    }
  }

  return {
    platform: 'android',
    user_id: input.user_id,
    productId: resolvedProductId,
    transactionId,
    originalTransactionId,
    expiresAt,
    status,
    rawPayload: {
      verifier: 'google_server_api',
      purchaseToken,
      packageName,
      apiResponse,
    },
  };
}
