import { Injectable } from '@nestjs/common';

import {
  BOOKING_LIST_TABS,
  mapStatusCountsToTabs,
} from '../bookings/booking-list-tabs.config';
import type { OverviewRangeQuery } from './dto/overview-query.dto';
import type { OverviewResponseDto } from './dto/overview-response.dto';
import type {
  OverviewBillingTabDto,
  OverviewBookingsTabDto,
  OverviewCustomersTabDto,
  OverviewOperationsTabDto,
  OverviewStaffTabDto,
} from './dto/overview-tab-response.dto';
import { OVERVIEW_RANGE_DAYS } from './overview.constants';
import { OverviewRepository } from './overview.repository';

@Injectable()
export class OverviewService {
  constructor(private readonly overviewRepository: OverviewRepository) {}

  private mapStatusCounts(statusCounts: Record<string, number>) {
    const pipelineTabs = mapStatusCountsToTabs(statusCounts);
    const bookingsByPipeline = BOOKING_LIST_TABS.filter(
      (tab) => tab.key !== 'all',
    ).map((tab) => ({
      stage: tab.key,
      count: pipelineTabs[tab.key],
    }));

    const bookingsByStatus = Object.entries(statusCounts)
      .map(([status, count]) => ({ status, count }))
      .sort((a, b) => b.count - a.count);

    return { bookingsByPipeline, bookingsByStatus };
  }

  async getDashboard(range: OverviewRangeQuery = '30d'): Promise<OverviewResponseDto> {
    const days = OVERVIEW_RANGE_DAYS[range];

    const [
      bookingKpis,
      operationsKpis,
      customerKpis,
      billingKpis,
      staffKpis,
      bookingTrend,
      statusCounts,
      paymentTrend,
      recentBookings,
    ] = await Promise.all([
      this.overviewRepository.getBookingKpis(),
      this.overviewRepository.getOperationsKpis(),
      this.overviewRepository.getCustomerKpis(),
      this.overviewRepository.getBillingKpis(),
      this.overviewRepository.getStaffKpis(),
      this.overviewRepository.getBookingTrend(days),
      this.overviewRepository.getStatusCounts(),
      this.overviewRepository.getPaymentTrend(days),
      this.overviewRepository.getRecentBookings(8),
    ]);

    const { bookingsByPipeline, bookingsByStatus } =
      this.mapStatusCounts(statusCounts);

    return {
      kpis: {
        bookings: bookingKpis,
        operations: operationsKpis,
        customers: customerKpis,
        billing: billingKpis,
        staff: staffKpis,
      },
      bookingTrend,
      bookingsByStatus,
      bookingsByPipeline,
      paymentTrend,
      recentBookings: recentBookings.map((row) => ({
        ...row,
        createdAt: row.createdAt.toISOString(),
      })),
      generatedAt: new Date().toISOString(),
    };
  }

  async getBookingsTab(range: OverviewRangeQuery = '30d'): Promise<OverviewBookingsTabDto> {
    const days = OVERVIEW_RANGE_DAYS[range];

    const [
      kpis,
      bookingTrend,
      statusCounts,
      bookingsByFreightType,
      bookingsByCurrency,
      recentBookings,
    ] = await Promise.all([
      this.overviewRepository.getBookingKpis(),
      this.overviewRepository.getBookingTrend(days),
      this.overviewRepository.getStatusCounts(),
      this.overviewRepository.getBookingsByFreightType(),
      this.overviewRepository.getBookingsByCurrency(),
      this.overviewRepository.getRecentBookings(8),
    ]);

    const { bookingsByPipeline, bookingsByStatus } =
      this.mapStatusCounts(statusCounts);

    return {
      kpis,
      bookingTrend,
      bookingsByStatus,
      bookingsByPipeline,
      bookingsByFreightType,
      bookingsByCurrency,
      recentBookings: recentBookings.map((row) => ({
        ...row,
        createdAt: row.createdAt.toISOString(),
      })),
      generatedAt: new Date().toISOString(),
    };
  }

  async getBillingTab(range: OverviewRangeQuery = '30d'): Promise<OverviewBillingTabDto> {
    const days = OVERVIEW_RANGE_DAYS[range];

    const [kpis, paymentTrend, paymentsByStatus, paymentsByMethod, revenueByCurrency] =
      await Promise.all([
        this.overviewRepository.getBillingKpis(),
        this.overviewRepository.getPaymentTrend(days),
        this.overviewRepository.getPaymentsByStatus(),
        this.overviewRepository.getPaymentsByMethod(),
        this.overviewRepository.getRevenueByCurrency(),
      ]);

    return {
      kpis,
      paymentTrend,
      paymentsByStatus,
      paymentsByMethod,
      revenueByCurrency,
      generatedAt: new Date().toISOString(),
    };
  }

  async getOperationsTab(): Promise<OverviewOperationsTabDto> {
    const [
      kpis,
      trainStatusBreakdown,
      wagonStatusBreakdown,
      containerStatusBreakdown,
      cargoStatusBreakdown,
    ] = await Promise.all([
      this.overviewRepository.getOperationsKpis(),
      this.overviewRepository.getTrainStatusBreakdown(),
      this.overviewRepository.getWagonStatusBreakdown(),
      this.overviewRepository.getContainerStatusBreakdown(),
      this.overviewRepository.getCargoStatusBreakdown(),
    ]);

    return {
      kpis,
      trainStatusBreakdown,
      wagonStatusBreakdown,
      containerStatusBreakdown,
      cargoStatusBreakdown,
      generatedAt: new Date().toISOString(),
    };
  }

  async getCustomersTab(range: OverviewRangeQuery = '30d'): Promise<OverviewCustomersTabDto> {
    const days = OVERVIEW_RANGE_DAYS[range];

    const [kpis, customerGrowthTrend, customersByType, topCustomersByBookings] =
      await Promise.all([
        this.overviewRepository.getCustomerKpis(),
        this.overviewRepository.getCustomerGrowthTrend(days),
        this.overviewRepository.getCustomersByType(),
        this.overviewRepository.getTopCustomersByBookings(8),
      ]);

    return {
      kpis,
      customerGrowthTrend,
      customersByType,
      topCustomersByBookings,
      generatedAt: new Date().toISOString(),
    };
  }

  async getStaffTab(range: OverviewRangeQuery = '30d'): Promise<OverviewStaffTabDto> {
    const days = OVERVIEW_RANGE_DAYS[range];

    const [kpis, usersByStatus, employeeGrowthTrend, activeUsersBreakdown] =
      await Promise.all([
        this.overviewRepository.getStaffKpis(),
        this.overviewRepository.getUsersByStatus(),
        this.overviewRepository.getEmployeeGrowthTrend(days),
        this.overviewRepository.getActiveUsersBreakdown(),
      ]);

    return {
      kpis,
      usersByStatus,
      employeeGrowthTrend,
      activeUsersBreakdown,
      generatedAt: new Date().toISOString(),
    };
  }
}
