import crypto from 'crypto';
import { PREMIUM_FEATURES, getPlan } from './plans.js';
import {
  createOrUpdateLicenseBySubscription,
  findLicenseByKey,
  findLicenseByCustomerId,
  updateLicense,
  grantOneTimeLicenseAtomic,
  claimLicenseMachine,
  isStripeTransitionStale
} from './store.js';

export function fingerprintMachine(payload = {}) {
  const parts = [
    payload.hostname || '',
    payload.platform || '',
    payload.arch || '',
    payload.cpu || '',
    payload.mac || ''
  ];
  return crypto.createHash('sha256').update(parts.join('|')).digest('hex').slice(0, 16);
}

/**
 * Sync a license from a Stripe subscription event. If the customer already
 * has a license (by customerId or email), EXTEND the existing license by
 * the plan duration instead of creating a new one. This is the "renewal
 * adds time to the same key" model.
 */
export function syncLicenseFromSubscription({ subscriptionId, customerId, customerEmail, planCode, status, currentPeriodEnd, durationDays, eventCreated, eventId }) {
  const premiumFeatures = Object.fromEntries(PREMIUM_FEATURES.map((f) => [f, true]));
  const existing = findLicenseByCustomerId(customerId);
  const incomingEvent = Number(eventCreated || 0);
  const previousEvent = Number(existing?.lastStripeEventCreated || 0);
  if (existing && isStripeTransitionStale(
    { ...existing, status: existing.subscriptionStatus || existing.status },
    incomingEvent,
    eventId,
    status
  )) {
    return { ...existing, staleEventIgnored: true };
  }

  return createOrUpdateLicenseBySubscription(subscriptionId, {
    subscriptionId,
    customerId,
    customerEmail,
    planCode,
    durationDays: durationDays || getPlan(planCode)?.durationDays,
    status,
    expiresAt: currentPeriodEnd,
    graceUntil: status === 'past_due' ? existing?.subscriptionGraceUntil || existing?.graceUntil || null : null,
    premiumFeatures,
    machineFingerprint: existing?.machineFingerprint || null,
    deactivatedAt: null,
    lastStripeEventCreated: incomingEvent ? Math.max(incomingEvent, previousEvent) : previousEvent || null,
    lastStripeEventId: eventId || existing?.lastStripeEventId || null
  });
}

/**
 * Grant a one-time license purchase. If the customer already has an active
 * license, EXTEND the existing license by durationDays instead of creating
 * a new one. This is the "buy again adds time to the same key" model.
 */
export function grantOneTimeLicense({ paymentIntentId, customerId, customerEmail, planCode, durationDays }) {
  const premiumFeatures = Object.fromEntries(PREMIUM_FEATURES.map((f) => [f, true]));
  return grantOneTimeLicenseAtomic({
    paymentIntentId,
    customerId,
    customerEmail,
    planCode,
    durationDays,
    premiumFeatures
  });
}

export function validateLicense({ code, machine }) {
  const license = findLicenseByKey(code);
  if (!license) {
    return { success: false, message: 'License not found' };
  }

  const now = Date.now();
  let graceActive = false;
  if (license.status === 'past_due') {
    if (!license.graceUntil) return { success: false, message: 'Payment is past due' };
    if (new Date(license.graceUntil).getTime() <= now) {
      updateLicense(license.id, { active: false, status: 'grace_expired' });
      return { success: false, message: 'Payment grace period has expired' };
    }
    graceActive = true;
  }
  if (!license.active) {
    return { success: false, message: 'License is not active' };
  }
  if (!graceActive && license.expiresAt && new Date(license.expiresAt).getTime() < now) {
    return { success: false, message: 'License has expired' };
  }

  const fingerprint = fingerprintMachine(machine || {});

  const machineClaim = claimLicenseMachine(code, fingerprint);
  if (!machineClaim.claimed) {
    return { success: false, message: 'License is already active on another machine' };
  }
  const updated = machineClaim.license;

  return {
    success: true,
    license: {
      id: updated.id,
      code: updated.key,
      tier: 'premium',
      expiresAt: updated.expiresAt,
      features: updated.premiumFeatures,
      subscriptionStatus: updated.status,
      customerEmail: updated.customerEmail
    },
    message: machineClaim.existing ? 'License validated' : 'License activated on this machine'
  };
}

export function deactivateLicense({ code, machine }) {
  const license = findLicenseByKey(code);
  if (!license) {
    return { success: false, message: 'License not found' };
  }

  const fingerprint = fingerprintMachine(machine || {});
  if (license.machineFingerprint && license.machineFingerprint !== fingerprint) {
    return { success: false, message: 'License is active on a different machine' };
  }

  const updated = updateLicense(license.id, {
    machineFingerprint: null,
    deactivatedAt: new Date().toISOString()
  });

  return { success: true, message: 'License deactivated', license: updated };
}
