import crypto from 'crypto';
import { PREMIUM_FEATURES } from './plans.js';
import {
  createOrUpdateLicenseBySubscription,
  findLicenseByKey,
  findActiveLicenseByCustomerEmail,
  findLicenseByCustomerId,
  extendLicenseByDuration,
  updateLicense
} 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 }) {
  const premiumFeatures = Object.fromEntries(PREMIUM_FEATURES.map((f) => [f, true]));

  // Try to find an existing license by customerId FIRST, then email
  const existing = findLicenseByCustomerId(customerId) || findActiveLicenseByCustomerEmail(customerEmail);

  if (existing) {
    // Extend existing license. We use currentPeriodEnd from Stripe for
    // subscriptions (Stripe is the authority on renewal dates), but if
    // durationDays is provided we use that to extend from current expiry.
    const patch = {
      subscriptionId,
      customerId,
      customerEmail,
      planCode,
      status,
      active: ['active', 'trialing', 'past_due'].includes(status),
      premiumFeatures,
      machineFingerprint: existing.machineFingerprint || null,
      deactivatedAt: null
    };
    if (currentPeriodEnd) {
      patch.expiresAt = currentPeriodEnd;
    }
    return updateLicense(existing.id, patch);
  }

  // No existing license — create one with the current period end as the initial expiry
  return createOrUpdateLicenseBySubscription(subscriptionId, {
    subscriptionId,
    customerId,
    customerEmail,
    planCode,
    status,
    expiresAt: currentPeriodEnd,
    active: ['active', 'trialing', 'past_due'].includes(status),
    premiumFeatures,
    machineFingerprint: null,
    deactivatedAt: 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]));

  // Look for existing license by customerId, then email
  const existing = findLicenseByCustomerId(customerId) || findActiveLicenseByCustomerEmail(customerEmail);

  if (existing) {
    // Extend existing license by the plan duration
    const extended = extendLicenseByDuration(existing.id, durationDays);
    return {
      ...extended,
      extended: true,
      addedDays: durationDays
    };
  }

  // No existing license — create one with expiry = now + durationDays
  const expiresAt = new Date();
  expiresAt.setUTCDate(expiresAt.getUTCDate() + durationDays);

  return createOrUpdateLicenseBySubscription(`one-time-${paymentIntentId}`, {
    subscriptionId: null,
    customerId,
    customerEmail,
    planCode,
    status: 'paid',
    expiresAt: expiresAt.toISOString(),
    active: true,
    premiumFeatures,
    machineFingerprint: null,
    deactivatedAt: null,
    paymentIntentId
  });
}

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

  if (!license.active) {
    return { success: false, message: 'License is not active' };
  }

  const now = Date.now();
  if (license.expiresAt && new Date(license.expiresAt).getTime() < now) {
    return { success: false, message: 'License has expired' };
  }

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

  if (license.machineFingerprint && license.machineFingerprint !== fingerprint) {
    return { success: false, message: 'License is already active on another machine' };
  }

  const updated = license.machineFingerprint
    ? license
    : updateLicense(license.id, { machineFingerprint: fingerprint, activatedAt: new Date().toISOString() });

  return {
    success: true,
    license: {
      code: updated.key,
      tier: 'premium',
      expiresAt: updated.expiresAt,
      features: updated.premiumFeatures,
      subscriptionStatus: updated.status,
      customerEmail: updated.customerEmail
    },
    message: updated === license ? '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 };
}
