import { Injectable, Logger } from '@nestjs/common';
import { PlentyoneConnector } from './plentyone.connector';
import {
  GetOrdersQueryDto,
  GetStockQueryDto,
  GetStatsQueryDto,
  PaginatedOrdersResponseDto,
  PaginatedStockResponseDto,
  OrderResponseDto,
  OrderStatsResponseDto,
  RevenueStatsResponseDto,
} from './dto';
import { ConnectionTestResult } from '../base-connector';

/**
 * Service layer for PlentyONE integration
 *
 * Provides business logic and data transformation for PlentyONE API calls.
 */
@Injectable()
export class PlentyoneService {
  private readonly logger = new Logger(PlentyoneService.name);

  constructor(private readonly connector: PlentyoneConnector) {}

  /**
   * Test the connection to PlentyONE
   */
  async testConnection(): Promise<ConnectionTestResult> {
    this.logger.log('Testing PlentyONE connection');
    return this.connector.testConnection();
  }

  /**
   * Check if PlentyONE integration is configured
   */
  isConfigured(): boolean {
    return this.connector.isConfigured();
  }

  /**
   * Get paginated list of orders
   */
  async getOrders(query: GetOrdersQueryDto): Promise<PaginatedOrdersResponseDto> {
    this.logger.log(`Fetching orders with query: ${JSON.stringify(query)}`);

    const response = await this.connector.getOrders({
      orderId: query.orderId,
      orderType: query.orderType,
      referrerId: query.referrerId,
      statusId: query.statusId,
      externalOrderId: query.externalOrderId,
      createdAtFrom: query.createdAtFrom,
      createdAtTo: query.createdAtTo,
      page: query.page,
      itemsPerPage: query.itemsPerPage,
      with: query.with,
    });

    return {
      page: response.page,
      totalsCount: response.totalsCount,
      isLastPage: response.isLastPage,
      itemsPerPage: response.itemsPerPage,
      entries: response.entries.map(this.mapOrderToDto),
    };
  }

  /**
   * Get a single order by ID
   */
  async getOrder(orderId: number): Promise<OrderResponseDto> {
    this.logger.log(`Fetching order ${orderId}`);

    const order = await this.connector.getOrder(orderId, [
      'amounts',
      'orderItems',
      'addresses',
    ]);

    return this.mapOrderToDto(order);
  }

  /**
   * Get paginated stock levels
   */
  async getStock(query: GetStockQueryDto): Promise<PaginatedStockResponseDto> {
    this.logger.log(`Fetching stock with query: ${JSON.stringify(query)}`);

    const response = await this.connector.getStock({
      variationId: query.variationId,
      itemId: query.itemId,
      warehouseId: query.warehouseId,
      page: query.page,
      itemsPerPage: query.itemsPerPage,
    });

    return {
      page: response.page,
      totalsCount: response.totalsCount,
      isLastPage: response.isLastPage,
      itemsPerPage: response.itemsPerPage,
      entries: response.entries.map((item) => ({
        itemId: item.itemId,
        variationId: item.variationId,
        warehouseId: item.warehouseId,
        warehouseName: item.warehouseName,
        stockPhysical: item.stockPhysical,
        reservedStock: item.reservedStock,
        stockNet: item.stockNet,
        reorderDelta: item.reorderDelta,
        updatedAt: item.updatedAt,
      })),
    };
  }

  /**
   * Get order statistics for a date range
   */
  async getOrderStats(query: GetStatsQueryDto): Promise<OrderStatsResponseDto> {
    this.logger.log(`Fetching order stats: ${query.dateFrom} to ${query.dateTo}`);

    const stats = await this.connector.getOrderStats({
      dateFrom: query.dateFrom,
      dateTo: query.dateTo,
      groupBy: query.groupBy,
      referrerId: query.referrerId,
      statusId: query.statusId,
    });

    return stats;
  }

  /**
   * Get revenue statistics grouped by date
   */
  async getRevenueStats(query: GetStatsQueryDto): Promise<RevenueStatsResponseDto[]> {
    this.logger.log(`Fetching revenue stats: ${query.dateFrom} to ${query.dateTo}`);

    return this.connector.getRevenueStats({
      dateFrom: query.dateFrom,
      dateTo: query.dateTo,
      groupBy: query.groupBy,
      referrerId: query.referrerId,
      statusId: query.statusId,
    });
  }

  /**
   * Get items with low stock
   */
  async getLowStockItems(warehouseId?: number): Promise<PaginatedStockResponseDto> {
    this.logger.log(`Fetching low stock items${warehouseId ? ` for warehouse ${warehouseId}` : ''}`);

    const items = await this.connector.getLowStockItems(warehouseId);

    return {
      page: 1,
      totalsCount: items.length,
      isLastPage: true,
      itemsPerPage: items.length,
      entries: items.map((item) => ({
        itemId: item.itemId,
        variationId: item.variationId,
        warehouseId: item.warehouseId,
        warehouseName: item.warehouseName,
        stockPhysical: item.stockPhysical,
        reservedStock: item.reservedStock,
        stockNet: item.stockNet,
        reorderDelta: item.reorderDelta,
        updatedAt: item.updatedAt,
      })),
    };
  }

  /**
   * Map PlentyONE order to response DTO
   */
  private mapOrderToDto(order: {
    id: number;
    typeId: number;
    statusId: number;
    statusName?: string;
    referrerId: number;
    createdAt: string;
    updatedAt: string;
    amounts?: Array<{
      currency: string;
      netTotal: number;
      grossTotal: number;
      vatTotal: number;
      paidAmount: number;
      shippingCostsGross: number;
      isSystemCurrency: boolean;
    }>;
    orderItems?: Array<{
      id: number;
      itemVariationId: number;
      quantity: number;
      orderItemName: string;
      amounts?: Array<{
        priceGross: number;
        priceNet: number;
      }>;
    }>;
  }): OrderResponseDto {
    return {
      id: order.id,
      typeId: order.typeId,
      statusId: order.statusId,
      statusName: order.statusName,
      referrerId: order.referrerId,
      createdAt: order.createdAt,
      updatedAt: order.updatedAt,
      amounts: order.amounts
        ?.filter((a) => a.isSystemCurrency)
        .map((a) => ({
          currency: a.currency,
          netTotal: a.netTotal,
          grossTotal: a.grossTotal,
          vatTotal: a.vatTotal,
          paidAmount: a.paidAmount,
          shippingCostsGross: a.shippingCostsGross,
        })),
      orderItems: order.orderItems?.map((item) => ({
        id: item.id,
        itemVariationId: item.itemVariationId,
        quantity: item.quantity,
        orderItemName: item.orderItemName,
        priceGross: item.amounts?.[0]?.priceGross,
        priceNet: item.amounts?.[0]?.priceNet,
      })),
    };
  }
}
