import fs from 'fs';
import path from 'path';
import crypto from 'crypto';

const DATA_DIR = process.env.DATA_DIR || path.resolve(process.cwd(), 'data');
const DATA_FILE = path.join(DATA_DIR, 'db.json');

function ensureStore() {
  fs.mkdirSync(DATA_DIR, { recursive: true });
  if (!fs.existsSync(DATA_FILE)) {
    fs.writeFileSync(DATA_FILE, JSON.stringify({ customers: {}, subscriptions: {}, licenses: {} }, null, 2));
  }
}

function readStore() {
  ensureStore();
  return JSON.parse(fs.readFileSync(DATA_FILE, 'utf8'));
}

function writeStore(db) {
  ensureStore();
  fs.writeFileSync(DATA_FILE, JSON.stringify(db, null, 2));
}

export function createLicenseKey() {
  const raw = crypto.randomBytes(16).toString('hex').toUpperCase();
  return `DC-${raw.slice(0,5)}-${raw.slice(5,10)}-${raw.slice(10,15)}-${raw.slice(15,20)}-${raw.slice(20,25)}`;
}

export function upsertCustomer(customer) {
  const db = readStore();
  db.customers[customer.id] = { ...(db.customers[customer.id] || {}), ...customer, updatedAt: new Date().toISOString() };
  writeStore(db);
  return db.customers[customer.id];
}

export function upsertSubscription(subscription) {
  const db = readStore();
  db.subscriptions[subscription.id] = { ...(db.subscriptions[subscription.id] || {}), ...subscription, updatedAt: new Date().toISOString() };
  writeStore(db);
  return db.subscriptions[subscription.id];
}

export function createOrUpdateLicenseBySubscription(subscriptionId, patch) {
  const db = readStore();
  const existing = Object.values(db.licenses).find((lic) => lic.subscriptionId === subscriptionId);
  const id = existing?.id || crypto.randomUUID();
  const next = {
    id,
    key: existing?.key || createLicenseKey(),
    createdAt: existing?.createdAt || new Date().toISOString(),
    ...existing,
    ...patch,
    updatedAt: new Date().toISOString()
  };
  db.licenses[id] = next;
  writeStore(db);
  return next;
}

export function findLicenseByKey(key) {
  const db = readStore();
  return Object.values(db.licenses).find((lic) => lic.key === key) || null;
}

/**
 * Find an active license by customer email. Used to EXTEND an existing
 * license when a customer buys again (so renewal adds time to the same key,
 * not a new one).
 */
export function findActiveLicenseByCustomerEmail(email) {
  if (!email) return null;
  const db = readStore();
  const normalized = email.toLowerCase();
  return Object.values(db.licenses).find((lic) =>
    lic.customerEmail && lic.customerEmail.toLowerCase() === normalized && lic.active
  ) || null;
}

/**
 * Find a license by Stripe customer ID. Used by webhook handlers to extend
 * the customer's existing license on subscription renewal.
 */
export function findLicenseByCustomerId(customerId) {
  if (!customerId) return null;
  const db = readStore();
  return Object.values(db.licenses).find((lic) => lic.customerId === customerId) || null;
}

/**
 * Extend an existing license by a number of days. If the license is expired,
 * the extension starts from now. Returns the updated license.
 */
export function extendLicenseByDuration(licenseId, days) {
  const db = readStore();
  const lic = db.licenses[licenseId];
  if (!lic) return null;
  const base = lic.expiresAt ? new Date(lic.expiresAt) : new Date();
  const now = Date.now();
  const start = base.getTime() > now ? base : new Date(now);
  start.setUTCDate(start.getUTCDate() + days);
  db.licenses[licenseId] = {
    ...lic,
    expiresAt: start.toISOString(),
    active: true,
    activatedAt: lic.activatedAt || new Date().toISOString(),
    updatedAt: new Date().toISOString()
  };
  writeStore(db);
  return db.licenses[licenseId];
}

export function updateLicense(id, patch) {
  const db = readStore();
  if (!db.licenses[id]) return null;
  db.licenses[id] = { ...db.licenses[id], ...patch, updatedAt: new Date().toISOString() };
  writeStore(db);
  return db.licenses[id];
}

export function getStoreSnapshot() {
  return readStore();
}
