import { db, Subscriber, Invoice, Payment } from '../../database/db';
import { WalletService } from './wallet.service';
import { NetworkDriverFactory } from '../network/driver.factory';
import { SubscriberDTO } from '../network/driver.interface';

export class BillingService {
  /**
   * Complete renewal flow for a subscriber:
   * 1. Row-locks subscriber and reseller wallet.
   * 2. Deducts wholesale cost from reseller pre-paid wallet if subscriber belongs to a reseller.
   * 3. Extends subscriber expiration_date by exactly 30 days from either NOW (if expired) or from existing expiration date.
   * 4. Updates status to 'active'.
   * 5. Creates paid invoice and payment record.
   * 6. Instantly activates subscriber profile on MikroTik or FreeRADIUS via INetworkDriver.
   */
  public static async renewSubscriberSubscription(params: {
    subscriberUsername: string;
    gateway: 'BKASH_PAYBILL' | 'BKASH_SIM_SMS' | 'NAGAD' | 'ROCKET' | 'MANUAL_CASH' | 'COLLECTOR_CASH';
    trxId: string;
    amountReceived?: number;
    rawPayload?: any;
  }) {
    const { subscriberUsername, gateway, trxId, amountReceived, rawPayload } = params;

    // Check for duplicate transaction ID
    const existingPayment = db.payments.find(p => p.trx_id === trxId);
    if (existingPayment) {
      throw new Error(`Transaction ID '${trxId}' has already been processed.`);
    }

    const subscriber = db.subscribers.find(s => s.username === subscriberUsername);
    if (!subscriber) {
      throw new Error(`Subscriber with username '${subscriberUsername}' not found.`);
    }

    const pkg = db.packages.find(p => p.id === subscriber.package_id);
    if (!pkg) {
      throw new Error(`Package configuration for subscriber '${subscriberUsername}' not found.`);
    }

    // Determine retail amount and wholesale cost
    let retailPrice = pkg.default_retail_price;
    if (subscriber.reseller_id) {
      const rp = db.reseller_packages.find(r => r.reseller_id === subscriber.reseller_id && r.package_id === pkg.id);
      if (rp) retailPrice = rp.custom_retail_price;
    }

    const effectiveAmount = amountReceived !== undefined ? amountReceived : retailPrice;

    // Perform atomic transaction with row locking
    return await db.withRowLock(`subscriber:${subscriber.id}`, async () => {
      let wholesaleDeductionResult: any = null;

      // Deduct wholesale price from reseller pre-paid wallet if applicable
      if (subscriber.reseller_id) {
        wholesaleDeductionResult = await WalletService.deductWholesale(
          subscriber.reseller_id,
          pkg.wholesale_price,
          subscriber.username,
          pkg.name
        );
      }

      // Calculate new expiration date (adds 30 days)
      const now = new Date();
      const currentExpiry = new Date(subscriber.expiration_date);
      let baseDate = now;
      if (currentExpiry.getTime() > now.getTime()) {
        baseDate = currentExpiry; // Extend from current future expiration date
      }
      const newExpiry = new Date(baseDate.getTime() + 30 * 24 * 60 * 60 * 1000).toISOString();

      subscriber.expiration_date = newExpiry;
      subscriber.status = 'active';
      subscriber.updated_at = new Date().toISOString();

      // Create or update invoice
      const invoiceNo = `INV-${Date.now().toString().slice(-6)}-${Math.floor(100 + Math.random() * 900)}`;
      const vat = Number((effectiveAmount * 0.05).toFixed(2));
      const invoice: Invoice = {
        id: `inv_${Date.now()}_${Math.random().toString(36).substring(2, 6)}`,
        invoice_no: invoiceNo,
        tenant_id: subscriber.tenant_id,
        reseller_id: subscriber.reseller_id,
        subscriber_id: subscriber.id,
        package_id: pkg.id,
        amount: effectiveAmount - vat,
        vat_amount: vat,
        discount_amount: 0.00,
        net_amount: effectiveAmount,
        status: 'paid',
        due_date: newExpiry,
        paid_at: new Date().toISOString(),
        payment_method: gateway,
        created_at: new Date().toISOString()
      };
      db.invoices.unshift(invoice);

      // Create payment record
      const payment: Payment = {
        id: `pay_${Date.now()}_${Math.random().toString(36).substring(2, 6)}`,
        invoice_id: invoice.id,
        subscriber_id: subscriber.id,
        reseller_id: subscriber.reseller_id,
        amount: effectiveAmount,
        gateway,
        trx_id: trxId,
        reference: subscriber.username,
        raw_payload: typeof rawPayload === 'object' ? JSON.stringify(rawPayload) : rawPayload,
        status: 'completed',
        created_at: new Date().toISOString()
      };
      db.payments.unshift(payment);

      // Dispatch instant network unblock / speed activation
      const subscriberDTO: SubscriberDTO = {
        id: subscriber.id,
        username: subscriber.username,
        driver_type: subscriber.driver_type,
        ip_address: subscriber.ip_address,
        mac_address: subscriber.mac_address,
        speed_mbps: pkg.speed_mbps,
        mikrotik_profile: pkg.mikrotik_profile_name,
        radius_group: pkg.radius_group_name,
        status: 'active'
      };

      const driverResult = await NetworkDriverFactory.executeAction('activateUser', subscriberDTO);

      db.logAudit(
        gateway === 'BKASH_PAYBILL' ? 'BKASH_GATEWAY' : 'SYSTEM',
        subscriber.id,
        'SUBSCRIBER_SUBSCRIPTION_RENEWED',
        {
          username: subscriber.username,
          gateway,
          trxId,
          amount: effectiveAmount,
          newExpiry,
          wholesaleDeductionResult,
          driverResult
        }
      );

      db.persist();

      return {
        success: true,
        message: `Subscription for ${subscriber.username} successfully renewed for 30 days.`,
        subscriber: {
          username: subscriber.username,
          status: subscriber.status,
          expiration_date: subscriber.expiration_date,
          package_name: pkg.name,
          speed_mbps: pkg.speed_mbps
        },
        invoice,
        payment,
        wholesaleDeducted: wholesaleDeductionResult ? pkg.wholesale_price : 0,
        networkSync: driverResult
      };
    });
  }

  /**
   * Fetches customer self-care billing desk data
   */
  public static getCustomerBillingDesk(subscriberId: string) {
    const subscriber = db.subscribers.find(s => s.id === subscriberId || s.username === subscriberId);
    if (!subscriber) {
      throw new Error(`Subscriber '${subscriberId}' not found`);
    }

    const pkg = db.packages.find(p => p.id === subscriber.package_id);
    const invoices = db.invoices.filter(i => i.subscriber_id === subscriber.id);
    const payments = db.payments.filter(p => p.subscriber_id === subscriber.id);
    const onu = subscriber.onu_id ? db.onus.find(o => o.id === subscriber.onu_id) : undefined;
    const reseller = subscriber.reseller_id ? db.resellers.find(r => r.id === subscriber.reseller_id) : undefined;
    const tenant = db.tenants.find(t => t.id === subscriber.tenant_id);

    return {
      subscriber: {
        id: subscriber.id,
        username: subscriber.username,
        full_name: subscriber.full_name,
        phone: subscriber.phone,
        email: subscriber.email,
        address: subscriber.address,
        driver_type: subscriber.driver_type,
        status: subscriber.status,
        expiration_date: subscriber.expiration_date,
        ip_address: subscriber.ip_address
      },
      package: pkg,
      onu,
      reseller: reseller ? {
        company_name: reseller.company_name,
        phone: reseller.phone,
        email: reseller.email,
        invoice_footer: reseller.invoice_footer
      } : null,
      tenant: tenant ? {
        name: tenant.name,
        invoice_footer: tenant.invoice_footer
      } : null,
      invoices,
      payments
    };
  }
}
