import { createHash } from 'crypto';
import { supabase } from './supabase.js';
import { logger } from './logger.js';
import type { LicenceRecord } from '../types/index.js';

const ALERT_WEBHOOK_URL = process.env.ALERT_WEBHOOK_URL ?? '';

async function sendQuotaAlert(
  licence: LicenceRecord,
  pct: number
): Promise<void> {
  const payload = {
    event:       'quota_alert',
    email:       licence.email,
    plan:        licence.plan,
    usage_month: licence.usage_month,
    quota_month: licence.quota_month,
    pct,
    reset_at:    licence.reset_at,
  };

  logger.warn('Quota alert', payload);

  if (ALERT_WEBHOOK_URL) {
    try {
      await fetch(ALERT_WEBHOOK_URL, {
        method:  'POST',
        headers: { 'Content-Type': 'application/json' },
        body:    JSON.stringify(payload),
      });
    } catch (err) {
      logger.error('Quota alert webhook failed', { err: String(err) });
    }
  }
}

export function hashKey(key: string): string {
  return createHash('sha256').update(key).digest('hex');
}

export async function validateLicence(
  licenceKey: string,
  clientIp: string,
  dolibarrDomain?: string,
): Promise<
  | { valid: true; licence: LicenceRecord }
  | { valid: false; reason: 'invalid' | 'inactive' | 'quota_exceeded' | 'ip_mismatch' | 'domain_mismatch' }
> {
  const keyHash = hashKey(licenceKey);

  const { data, error } = await supabase
    .from('licences')
    .select('*')
    .eq('key_hash', keyHash)
    .single();

  if (error || !data) {
    return { valid: false, reason: 'invalid' };
  }

  const licence = data as LicenceRecord;

  if (!licence.active) {
    return { valid: false, reason: 'inactive' };
  }

  if (licence.flagged) {
    logger.warn('Flagged licence attempted', { id: licence.id, email: licence.email });
    return { valid: false, reason: 'inactive' };
  }

  // Monthly reset
  const resetAt = new Date(licence.reset_at);
  if (new Date() > resetAt) {
    await supabase
      .from('licences')
      .update({ usage_month: 0, reset_at: nextMonthReset() })
      .eq('id', licence.id);
    licence.usage_month = 0;
  }

  if (licence.usage_month >= licence.quota_month) {
    return { valid: false, reason: 'quota_exceeded' };
  }

  // Optional IP binding
  if (licence.allowed_ip && licence.allowed_ip !== clientIp) {
    return { valid: false, reason: 'ip_mismatch' };
  }

  // Domain binding: lock on first use, reject on mismatch
  if (dolibarrDomain) {
    const domain = dolibarrDomain.toLowerCase().replace(/^https?:\/\//, '').split('/')[0];
    if (!licence.domain_lock) {
      await supabase
        .from('licences')
        .update({ domain_lock: domain })
        .eq('id', licence.id);
      licence.domain_lock = domain;
    } else if (licence.domain_lock !== domain) {
      logger.warn('Domain mismatch on licence', { id: licence.id, locked: licence.domain_lock, attempted: domain });
      return { valid: false, reason: 'domain_mismatch' };
    }
  }

  return { valid: true, licence };
}

export async function incrementUsage(
  licenceId: string,
  usageData: {
    nb_photos: number;
    nb_lignes: number;
    latency_ms: number;
    key_hash: string;
  }
): Promise<void> {
  await Promise.all([
    supabase.rpc('increment_usage', { licence_id: licenceId }),
    supabase.from('usage_logs').insert({
      licence_id: licenceId,
      key_hash:   usageData.key_hash,
      nb_photos:  usageData.nb_photos,
      nb_lignes:  usageData.nb_lignes,
      latency_ms: usageData.latency_ms,
      created_at: new Date().toISOString(),
    }),
  ]);

  // Fetch fresh usage for quota alerts
  const { data: fresh } = await supabase
    .from('licences')
    .select('email, plan, usage_month, quota_month, reset_at')
    .eq('id', licenceId)
    .single();

  if (fresh && fresh.quota_month > 0) {
    const pct = Math.round((fresh.usage_month / fresh.quota_month) * 100);
    const wasBelow80 = ((fresh.usage_month - 1) / fresh.quota_month) < 0.80;
    const wasBelow100 = (fresh.usage_month - 1) < fresh.quota_month;

    if (pct >= 100 && wasBelow100) {
      await sendQuotaAlert(fresh as unknown as LicenceRecord, 100);
    } else if (pct >= 80 && wasBelow80) {
      await sendQuotaAlert(fresh as unknown as LicenceRecord, 80);
    }
  }

  // Flag if > 50 generations in 24h (abuse detection)
  const dayAgo = new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString();
  const { count } = await supabase
    .from('usage_logs')
    .select('*', { count: 'exact', head: true })
    .eq('licence_id', licenceId)
    .gte('created_at', dayAgo);

  if (count && count > 50) {
    await supabase.from('licences').update({ flagged: true }).eq('id', licenceId);
  }
}

function nextMonthReset(): string {
  const d = new Date();
  d.setMonth(d.getMonth() + 1);
  d.setDate(1);
  d.setHours(0, 0, 0, 0);
  return d.toISOString();
}
