// Re-export new services
export { ReportsService } from './reports.service';
export { ReportExecutionService } from './report-execution.service';
export { ReportSchedulerService } from './report-scheduler.service';
export { DashboardsService } from './dashboards.service';

// Legacy types and service (kept for backwards compatibility)
import { DataSource } from 'typeorm';

export interface ReportDateRange {
  startDate: Date;
  endDate: Date;
}

export interface SalesReportParams {
  tenantId: string;
  startDate: Date;
  endDate: Date;
  partnerId?: string;
  productId?: string;
  groupBy?: 'day' | 'week' | 'month' | 'partner' | 'product';
}

export interface InventoryReportParams {
  tenantId: string;
  warehouseId?: string;
  productId?: string;
  categoryId?: string;
  lowStockOnly?: boolean;
}

export interface FinancialReportParams {
  tenantId: string;
  startDate: Date;
  endDate: Date;
  reportType: 'income' | 'expenses' | 'profit_loss' | 'cash_flow' | 'accounts_receivable' | 'accounts_payable';
}

export interface SalesSummary {
  totalOrders: number;
  totalRevenue: number;
  averageOrderValue: number;
  totalItems: number;
}

export interface InventorySummary {
  totalProducts: number;
  totalValue: number;
  lowStockItems: number;
  outOfStockItems: number;
}

export interface FinancialSummary {
  totalIncome: number;
  totalExpenses: number;
  netProfit: number;
  margin: number;
}

export class LegacyReportsService {
  constructor(private readonly dataSource: DataSource) {}

  // ==================== Sales Reports ====================

  async getSalesReport(params: SalesReportParams): Promise<{
    summary: SalesSummary;
    data: any[];
    period: ReportDateRange;
  }> {
    const { tenantId, startDate, endDate, partnerId, productId, groupBy = 'day' } = params;

    // Build query based on groupBy
    let query = `
      SELECT
        COUNT(DISTINCT o.id) as order_count,
        SUM(o.total) as total_revenue,
        SUM(oi.quantity) as total_items
      FROM sales.sales_orders o
      LEFT JOIN sales.sales_order_items oi ON o.id = oi.order_id
      WHERE o.tenant_id = $1
        AND o.status NOT IN ('cancelled', 'draft')
        AND o.order_date BETWEEN $2 AND $3
    `;

    const queryParams: any[] = [tenantId, startDate, endDate];
    let paramIndex = 4;

    if (partnerId) {
      query += ` AND o.partner_id = $${paramIndex}`;
      queryParams.push(partnerId);
      paramIndex++;
    }

    if (productId) {
      query += ` AND oi.product_id = $${paramIndex}`;
      queryParams.push(productId);
    }

    try {
      const result = await this.dataSource.query(query, queryParams);
      const row = result[0] || {};

      const summary: SalesSummary = {
        totalOrders: parseInt(row.order_count) || 0,
        totalRevenue: parseFloat(row.total_revenue) || 0,
        averageOrderValue: row.order_count > 0 ? parseFloat(row.total_revenue) / parseInt(row.order_count) : 0,
        totalItems: parseInt(row.total_items) || 0,
      };

      // Get detailed data grouped by period
      const detailQuery = this.buildSalesDetailQuery(groupBy);
      const detailParams = [tenantId, startDate, endDate];
      const detailData = await this.dataSource.query(detailQuery, detailParams);

      return {
        summary,
        data: detailData,
        period: { startDate, endDate },
      };
    } catch (error) {
      // Return empty data if tables don't exist yet
      return {
        summary: { totalOrders: 0, totalRevenue: 0, averageOrderValue: 0, totalItems: 0 },
        data: [],
        period: { startDate, endDate },
      };
    }
  }

  private buildSalesDetailQuery(groupBy: string): string {
    const groupByClause = {
      day: "DATE_TRUNC('day', o.order_date)",
      week: "DATE_TRUNC('week', o.order_date)",
      month: "DATE_TRUNC('month', o.order_date)",
      partner: 'o.partner_id',
      product: 'oi.product_id',
    }[groupBy] || "DATE_TRUNC('day', o.order_date)";

    return `
      SELECT
        ${groupByClause} as period,
        COUNT(DISTINCT o.id) as order_count,
        SUM(o.total) as total_revenue
      FROM sales.sales_orders o
      LEFT JOIN sales.sales_order_items oi ON o.id = oi.order_id
      WHERE o.tenant_id = $1
        AND o.status NOT IN ('cancelled', 'draft')
        AND o.order_date BETWEEN $2 AND $3
      GROUP BY ${groupByClause}
      ORDER BY period DESC
    `;
  }

  async getTopSellingProducts(
    tenantId: string,
    startDate: Date,
    endDate: Date,
    limit: number = 10
  ): Promise<any[]> {
    try {
      const query = `
        SELECT
          oi.product_id,
          oi.product_name,
          SUM(oi.quantity) as total_quantity,
          SUM(oi.line_total) as total_revenue
        FROM sales.sales_order_items oi
        JOIN sales.sales_orders o ON oi.order_id = o.id
        WHERE o.tenant_id = $1
          AND o.status NOT IN ('cancelled', 'draft')
          AND o.order_date BETWEEN $2 AND $3
        GROUP BY oi.product_id, oi.product_name
        ORDER BY total_revenue DESC
        LIMIT $4
      `;

      return await this.dataSource.query(query, [tenantId, startDate, endDate, limit]);
    } catch {
      return [];
    }
  }

  async getTopCustomers(
    tenantId: string,
    startDate: Date,
    endDate: Date,
    limit: number = 10
  ): Promise<any[]> {
    try {
      const query = `
        SELECT
          o.partner_id,
          o.partner_name,
          COUNT(o.id) as order_count,
          SUM(o.total) as total_revenue
        FROM sales.sales_orders o
        WHERE o.tenant_id = $1
          AND o.status NOT IN ('cancelled', 'draft')
          AND o.order_date BETWEEN $2 AND $3
        GROUP BY o.partner_id, o.partner_name
        ORDER BY total_revenue DESC
        LIMIT $4
      `;

      return await this.dataSource.query(query, [tenantId, startDate, endDate, limit]);
    } catch {
      return [];
    }
  }

  // ==================== Inventory Reports ====================

  async getInventoryReport(params: InventoryReportParams): Promise<{
    summary: InventorySummary;
    data: any[];
  }> {
    const { tenantId, warehouseId, productId, categoryId, lowStockOnly } = params;

    try {
      let query = `
        SELECT
          COUNT(DISTINCT sl.product_id) as total_products,
          SUM(sl.quantity_on_hand * COALESCE(sl.unit_cost, 0)) as total_value,
          COUNT(CASE WHEN sl.quantity_on_hand <= 0 THEN 1 END) as out_of_stock,
          COUNT(CASE WHEN sl.quantity_on_hand > 0 AND sl.quantity_on_hand <= 10 THEN 1 END) as low_stock
        FROM inventory.stock_levels sl
        WHERE sl.tenant_id = $1
      `;

      const queryParams: any[] = [tenantId];
      let paramIndex = 2;

      if (warehouseId) {
        query += ` AND sl.warehouse_id = $${paramIndex}`;
        queryParams.push(warehouseId);
        paramIndex++;
      }

      if (productId) {
        query += ` AND sl.product_id = $${paramIndex}`;
        queryParams.push(productId);
      }

      const result = await this.dataSource.query(query, queryParams);
      const row = result[0] || {};

      const summary: InventorySummary = {
        totalProducts: parseInt(row.total_products) || 0,
        totalValue: parseFloat(row.total_value) || 0,
        lowStockItems: parseInt(row.low_stock) || 0,
        outOfStockItems: parseInt(row.out_of_stock) || 0,
      };

      // Get detailed stock levels
      let detailQuery = `
        SELECT
          sl.product_id,
          p.name as product_name,
          p.sku,
          sl.warehouse_id,
          w.name as warehouse_name,
          sl.quantity_on_hand,
          sl.quantity_reserved,
          sl.quantity_available,
          sl.unit_cost,
          (sl.quantity_on_hand * COALESCE(sl.unit_cost, 0)) as total_value
        FROM inventory.stock_levels sl
        LEFT JOIN products.products p ON sl.product_id = p.id
        LEFT JOIN inventory.warehouses w ON sl.warehouse_id = w.id
        WHERE sl.tenant_id = $1
      `;

      const detailParams: any[] = [tenantId];
      let detailIndex = 2;

      if (warehouseId) {
        detailQuery += ` AND sl.warehouse_id = $${detailIndex}`;
        detailParams.push(warehouseId);
        detailIndex++;
      }

      if (lowStockOnly) {
        detailQuery += ` AND sl.quantity_on_hand <= 10`;
      }

      detailQuery += ` ORDER BY sl.quantity_on_hand ASC LIMIT 100`;

      const detailData = await this.dataSource.query(detailQuery, detailParams);

      return { summary, data: detailData };
    } catch {
      return {
        summary: { totalProducts: 0, totalValue: 0, lowStockItems: 0, outOfStockItems: 0 },
        data: [],
      };
    }
  }

  async getStockMovementReport(
    tenantId: string,
    startDate: Date,
    endDate: Date,
    warehouseId?: string
  ): Promise<any[]> {
    try {
      let query = `
        SELECT
          sm.movement_type,
          COUNT(*) as movement_count,
          SUM(sm.quantity) as total_quantity,
          SUM(sm.total_cost) as total_value
        FROM inventory.stock_movements sm
        WHERE sm.tenant_id = $1
          AND sm.status = 'confirmed'
          AND sm.created_at BETWEEN $2 AND $3
      `;

      const params: any[] = [tenantId, startDate, endDate];

      if (warehouseId) {
        query += ` AND (sm.source_warehouse_id = $4 OR sm.dest_warehouse_id = $4)`;
        params.push(warehouseId);
      }

      query += ` GROUP BY sm.movement_type ORDER BY total_quantity DESC`;

      return await this.dataSource.query(query, params);
    } catch {
      return [];
    }
  }

  // ==================== Financial Reports ====================

  async getFinancialReport(params: FinancialReportParams): Promise<{
    summary: FinancialSummary;
    data: any[];
    period: ReportDateRange;
  }> {
    const { tenantId, startDate, endDate, reportType } = params;

    try {
      switch (reportType) {
        case 'income':
          return await this.getIncomeReport(tenantId, startDate, endDate);
        case 'expenses':
          return await this.getExpensesReport(tenantId, startDate, endDate);
        case 'profit_loss':
          return await this.getProfitLossReport(tenantId, startDate, endDate);
        case 'accounts_receivable':
          return await this.getAccountsReceivableReport(tenantId);
        case 'accounts_payable':
          return await this.getAccountsPayableReport(tenantId);
        default:
          return await this.getProfitLossReport(tenantId, startDate, endDate);
      }
    } catch {
      return {
        summary: { totalIncome: 0, totalExpenses: 0, netProfit: 0, margin: 0 },
        data: [],
        period: { startDate, endDate },
      };
    }
  }

  private async getIncomeReport(
    tenantId: string,
    startDate: Date,
    endDate: Date
  ): Promise<{ summary: FinancialSummary; data: any[]; period: ReportDateRange }> {
    const query = `
      SELECT
        DATE_TRUNC('month', i.invoice_date) as period,
        SUM(i.total) as total_income
      FROM billing.invoices i
      WHERE i.tenant_id = $1
        AND i.invoice_type = 'sale'
        AND i.status NOT IN ('cancelled', 'voided', 'draft')
        AND i.invoice_date BETWEEN $2 AND $3
      GROUP BY DATE_TRUNC('month', i.invoice_date)
      ORDER BY period
    `;

    const data = await this.dataSource.query(query, [tenantId, startDate, endDate]);
    const totalIncome = data.reduce((sum: number, row: any) => sum + parseFloat(row.total_income || 0), 0);

    return {
      summary: { totalIncome, totalExpenses: 0, netProfit: totalIncome, margin: 100 },
      data,
      period: { startDate, endDate },
    };
  }

  private async getExpensesReport(
    tenantId: string,
    startDate: Date,
    endDate: Date
  ): Promise<{ summary: FinancialSummary; data: any[]; period: ReportDateRange }> {
    const query = `
      SELECT
        DATE_TRUNC('month', i.invoice_date) as period,
        SUM(i.total) as total_expenses
      FROM billing.invoices i
      WHERE i.tenant_id = $1
        AND i.invoice_type = 'purchase'
        AND i.status NOT IN ('cancelled', 'voided', 'draft')
        AND i.invoice_date BETWEEN $2 AND $3
      GROUP BY DATE_TRUNC('month', i.invoice_date)
      ORDER BY period
    `;

    const data = await this.dataSource.query(query, [tenantId, startDate, endDate]);
    const totalExpenses = data.reduce((sum: number, row: any) => sum + parseFloat(row.total_expenses || 0), 0);

    return {
      summary: { totalIncome: 0, totalExpenses, netProfit: -totalExpenses, margin: 0 },
      data,
      period: { startDate, endDate },
    };
  }

  private async getProfitLossReport(
    tenantId: string,
    startDate: Date,
    endDate: Date
  ): Promise<{ summary: FinancialSummary; data: any[]; period: ReportDateRange }> {
    const incomeQuery = `
      SELECT COALESCE(SUM(total), 0) as total
      FROM billing.invoices
      WHERE tenant_id = $1
        AND invoice_type = 'sale'
        AND status NOT IN ('cancelled', 'voided', 'draft')
        AND invoice_date BETWEEN $2 AND $3
    `;

    const expensesQuery = `
      SELECT COALESCE(SUM(total), 0) as total
      FROM billing.invoices
      WHERE tenant_id = $1
        AND invoice_type = 'purchase'
        AND status NOT IN ('cancelled', 'voided', 'draft')
        AND invoice_date BETWEEN $2 AND $3
    `;

    const [incomeResult, expensesResult] = await Promise.all([
      this.dataSource.query(incomeQuery, [tenantId, startDate, endDate]),
      this.dataSource.query(expensesQuery, [tenantId, startDate, endDate]),
    ]);

    const totalIncome = parseFloat(incomeResult[0]?.total) || 0;
    const totalExpenses = parseFloat(expensesResult[0]?.total) || 0;
    const netProfit = totalIncome - totalExpenses;
    const margin = totalIncome > 0 ? (netProfit / totalIncome) * 100 : 0;

    return {
      summary: { totalIncome, totalExpenses, netProfit, margin },
      data: [{ totalIncome, totalExpenses, netProfit, margin }],
      period: { startDate, endDate },
    };
  }

  private async getAccountsReceivableReport(
    tenantId: string
  ): Promise<{ summary: FinancialSummary; data: any[]; period: ReportDateRange }> {
    const query = `
      SELECT
        i.id,
        i.invoice_number,
        i.partner_name,
        i.total,
        i.amount_paid,
        (i.total - i.amount_paid) as amount_due,
        i.due_date,
        CASE
          WHEN i.due_date < CURRENT_DATE THEN 'overdue'
          WHEN i.due_date < CURRENT_DATE + INTERVAL '7 days' THEN 'due_soon'
          ELSE 'current'
        END as status
      FROM billing.invoices i
      WHERE i.tenant_id = $1
        AND i.invoice_type = 'sale'
        AND i.status IN ('validated', 'sent', 'partial')
        AND (i.total - i.amount_paid) > 0
      ORDER BY i.due_date ASC
    `;

    const data = await this.dataSource.query(query, [tenantId]);
    const totalIncome = data.reduce((sum: number, row: any) => sum + parseFloat(row.amount_due || 0), 0);

    const now = new Date();
    return {
      summary: { totalIncome, totalExpenses: 0, netProfit: totalIncome, margin: 0 },
      data,
      period: { startDate: now, endDate: now },
    };
  }

  private async getAccountsPayableReport(
    tenantId: string
  ): Promise<{ summary: FinancialSummary; data: any[]; period: ReportDateRange }> {
    const query = `
      SELECT
        i.id,
        i.invoice_number,
        i.partner_name,
        i.total,
        i.amount_paid,
        (i.total - i.amount_paid) as amount_due,
        i.due_date,
        CASE
          WHEN i.due_date < CURRENT_DATE THEN 'overdue'
          WHEN i.due_date < CURRENT_DATE + INTERVAL '7 days' THEN 'due_soon'
          ELSE 'current'
        END as status
      FROM billing.invoices i
      WHERE i.tenant_id = $1
        AND i.invoice_type = 'purchase'
        AND i.status IN ('validated', 'sent', 'partial')
        AND (i.total - i.amount_paid) > 0
      ORDER BY i.due_date ASC
    `;

    const data = await this.dataSource.query(query, [tenantId]);
    const totalExpenses = data.reduce((sum: number, row: any) => sum + parseFloat(row.amount_due || 0), 0);

    const now = new Date();
    return {
      summary: { totalIncome: 0, totalExpenses, netProfit: -totalExpenses, margin: 0 },
      data,
      period: { startDate: now, endDate: now },
    };
  }
}
