import db from '../config/database';
import { DomainEventBus } from '../core/runtime/DomainEventBus';
import { logger } from '../utils/logger';

export interface CostTemplate {
  id: string;
  tenantId: string;
  name: string;
  category: string;
  platform: string;
  costItems: CostItem[];
  isActive: boolean;
  createdAt: string;
  updatedAt: string;
}

export interface CostItem {
  name: string;
  type: 'FIXED' | 'PERCENTAGE' | 'PER_UNIT';
  value: number;
  currency: string;
}

export class CostTemplateService {
  private static TABLE = 'cf_cost_template';

  static async initTable(): Promise<void> {
    const hasTable = await db.schema.hasTable(this.TABLE);
    if (!hasTable) {
      await db.schema.createTable(this.TABLE, (table) => {
        table.string('id', 64).primary();
        table.string('tenant_id', 64).notNullable();
        table.string('name', 128).notNullable();
        table.string('category', 64);
        table.string('platform', 64);
        table.json('cost_items');
        table.boolean('is_active').defaultTo(true);
        table.timestamps(true, true);
        table.index(['tenant_id', 'platform']);
        table.index(['tenant_id', 'category']);
      });
    }
  }

  static async list(tenantId: string, filters?: { platform?: string; category?: string }): Promise<CostTemplate[]> {
    let query = db(this.TABLE).where('tenant_id', tenantId);
    if (filters?.platform) query = query.where('platform', filters.platform);
    if (filters?.category) query = query.where('category', filters.category);
    return query.orderBy('created_at', 'desc');
  }

  static async getById(id: string): Promise<CostTemplate | null> {
    const template = await db(this.TABLE).where({ id }).first();
    return template || null;
  }

  static async create(tenantId: string, data: {
    name: string;
    category: string;
    platform: string;
    costItems: CostItem[];
    isActive?: boolean;
  }): Promise<CostTemplate> {
    const id = this.generateId();
    const now = new Date().toISOString();
    const template: CostTemplate = {
      id,
      tenantId,
      name: data.name,
      category: data.category,
      platform: data.platform,
      costItems: data.costItems,
      isActive: data.isActive ?? true,
      createdAt: now,
      updatedAt: now,
    };
    await db(this.TABLE).insert({
      id: template.id,
      tenant_id: template.tenantId,
      name: template.name,
      category: template.category,
      platform: template.platform,
      cost_items: JSON.stringify(template.costItems),
      is_active: template.isActive,
      created_at: template.createdAt,
      updated_at: template.updatedAt,
    });
    await DomainEventBus.publish('cost_template.created', { templateId: id, tenantId });
    return template;
  }

  static async update(id: string, data: Partial<CostTemplate>): Promise<CostTemplate> {
    const updateData: Record<string, any> = { updated_at: new Date().toISOString() };
    if (data.name) updateData.name = data.name;
    if (data.category) updateData.category = data.category;
    if (data.platform) updateData.platform = data.platform;
    if (data.costItems) updateData.cost_items = JSON.stringify(data.costItems);
    if (data.isActive !== undefined) updateData.is_active = data.isActive;
    await db(this.TABLE).where({ id }).update(updateData);
    const template = await this.getById(id);
    await DomainEventBus.publish('cost_template.updated', { templateId: id });
    return template!;
  }

  static async delete(id: string): Promise<void> {
    await db(this.TABLE).where({ id }).delete();
    await DomainEventBus.publish('cost_template.deleted', { templateId: id });
  }

  static async duplicate(id: string): Promise<CostTemplate> {
    const original = await this.getById(id);
    if (!original) throw new Error('Template not found');
    return this.create(original.tenantId, {
      name: `${original.name} (Copy)`,
      category: original.category,
      platform: original.platform,
      costItems: original.costItems,
      isActive: false,
    });
  }

  static async calculateCost(templateId: string, basePrice: number, quantity: number = 1): Promise<{
    totalCost: number;
    breakdown: { name: string; type: string; amount: number }[];
  }> {
    const template = await this.getById(templateId);
    if (!template) throw new Error('Template not found');
    const breakdown: { name: string; type: string; amount: number }[] = [];
    let totalCost = 0;
    for (const item of template.costItems) {
      let amount = 0;
      switch (item.type) {
        case 'FIXED':
          amount = item.value;
          break;
        case 'PERCENTAGE':
          amount = (basePrice * item.value) / 100;
          break;
        case 'PER_UNIT':
          amount = item.value * quantity;
          break;
      }
      breakdown.push({ name: item.name, type: item.type, amount });
      totalCost += amount;
    }
    return { totalCost, breakdown };
  }

  private static generateId(): string {
    return `ct_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
  }
}
