import {
  Controller,
  Get,
  Post,
  Body,
  Param,
  Query,
  UseGuards,
  UsePipes,
  ValidationPipe,
  HttpStatus,
  Logger,
  ParseIntPipe,
  ParseUUIDPipe,
  DefaultValuePipe,
  ParseEnumPipe,
} from '@nestjs/common';
import {
  ApiTags,
  ApiOperation,
  ApiResponse,
  ApiBearerAuth,
  ApiQuery,
  ApiParam,
} from '@nestjs/swagger';
import { SalesService } from './sales.service';
import { CreateSaleDto } from './dto/create-sale.dto';
import { SaleResponseDto, SalesSummaryDto } from './dto/sale-response.dto';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
import { TenantGuard } from '../auth/guards/tenant.guard';
import { CurrentUser } from '../auth/decorators/current-user.decorator';
import { AuthenticatedUser } from '../auth/guards/tenant.guard';
import { SaleStatus } from '@prisma/client';

@ApiTags('Sales')
@ApiBearerAuth()
@Controller('sales')
@UseGuards(JwtAuthGuard, TenantGuard)
export class SalesController {
  private readonly logger = new Logger(SalesController.name);

  constructor(private readonly salesService: SalesService) {}

  @Post()
  @ApiOperation({
    summary: 'Create a new sale',
    description: 'Processes a new sale transaction with inventory management and audit trail',
  })
  @ApiResponse({
    status: HttpStatus.CREATED,
    description: 'Sale created successfully',
    type: SaleResponseDto,
  })
  @ApiResponse({
    status: HttpStatus.BAD_REQUEST,
    description: 'Invalid input data or business rule violation',
    schema: {
      type: 'object',
      properties: {
        statusCode: { type: 'number', example: 400 },
        message: { type: 'string', example: 'Sale must contain at least one item' },
        error: { type: 'string', example: 'Bad Request' },
      },
    },
  })
  @ApiResponse({
    status: HttpStatus.CONFLICT,
    description: 'Insufficient stock or other conflict',
    schema: {
      type: 'object',
      properties: {
        statusCode: { type: 'number', example: 409 },
        message: { 
          type: 'string', 
          example: 'Insufficient stock for product \"Coffee Beans\". Available: 5, Requested: 10' 
        },
        error: { type: 'string', example: 'Conflict' },
      },
    },
  })
  @ApiResponse({
    status: HttpStatus.NOT_FOUND,
    description: 'Product not found or inactive',
    schema: {
      type: 'object',
      properties: {
        statusCode: { type: 'number', example: 404 },
        message: { 
          type: 'string', 
          example: 'Products not found or inactive: a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11' 
        },
        error: { type: 'string', example: 'Not Found' },
      },
    },
  })
  @ApiResponse({
    status: HttpStatus.UNAUTHORIZED,
    description: 'Invalid or expired JWT token',
  })
  @ApiResponse({
    status: HttpStatus.FORBIDDEN,
    description: 'User does not have access to this tenant',
  })
  @UsePipes(new ValidationPipe({ 
    transform: true, 
    whitelist: true,
    forbidNonWhitelisted: true,
  }))
  async create(
    @Body() createSaleDto: CreateSaleDto,
    @CurrentUser() user: AuthenticatedUser,
  ): Promise<SaleResponseDto> {
    this.logger.log(`Creating sale for user ${user.id} in tenant ${user.tenantId}`);
    
    const sale = await this.salesService.createSale(createSaleDto, user);
    
    this.logger.log(`Sale created: ${sale.saleNumber}`);
    return sale;
  }

  @Get()
  @ApiOperation({
    summary: 'Get all sales for the current tenant',
    description: 'Retrieves paginated list of sales with optional filtering',
  })
  @ApiQuery({
    name: 'page',
    required: false,
    type: Number,
    description: 'Page number (1-based)',
    example: 1,
  })
  @ApiQuery({
    name: 'limit',
    required: false,
    type: Number,
    description: 'Number of items per page',
    example: 20,
  })
  @ApiQuery({
    name: 'status',
    required: false,
    enum: SaleStatus,
    description: 'Filter by sale status',
  })
  @ApiQuery({
    name: 'startDate',
    required: false,
    type: String,
    description: 'Filter sales from this date (ISO string)',
    example: '2024-01-01T00:00:00.000Z',
  })
  @ApiQuery({
    name: 'endDate',
    required: false,
    type: String,
    description: 'Filter sales until this date (ISO string)',
    example: '2024-12-31T23:59:59.999Z',
  })
  @ApiResponse({
    status: HttpStatus.OK,
    description: 'List of sales retrieved successfully',
    schema: {
      type: 'object',
      properties: {
        sales: {
          type: 'array',
          items: { $ref: '#/components/schemas/SaleResponseDto' },
        },
        total: { type: 'number', example: 150 },
        page: { type: 'number', example: 1 },
        limit: { type: 'number', example: 20 },
        totalPages: { type: 'number', example: 8 },
      },
    },
  })
  async findAll(
    @Query('page', new DefaultValuePipe(1), ParseIntPipe) page: number,
    @Query('limit', new DefaultValuePipe(20), ParseIntPipe) limit: number,
    @Query('status', new DefaultValuePipe(undefined)) status?: SaleStatus,
    @Query('startDate') startDateStr?: string,
    @Query('endDate') endDateStr?: string,
    @CurrentUser() user: AuthenticatedUser,
  ) {
    this.logger.log(`Fetching sales for tenant ${user.tenantId}, page ${page}, limit ${limit}`);

    // Validate and parse dates
    let startDate: Date | undefined;
    let endDate: Date | undefined;

    if (startDateStr) {
      startDate = new Date(startDateStr);
      if (isNaN(startDate.getTime())) {
        throw new Error('Invalid startDate format');
      }
    }

    if (endDateStr) {
      endDate = new Date(endDateStr);
      if (isNaN(endDate.getTime())) {
        throw new Error('Invalid endDate format');
      }
    }

    // Validate page and limit
    if (page < 1) page = 1;
    if (limit < 1) limit = 20;
    if (limit > 100) limit = 100; // Prevent excessive data loading

    const { sales, total } = await this.salesService.findAll(
      user,
      page,
      limit,
      status,
      startDate,
      endDate,
    );

    const totalPages = Math.ceil(total / limit);

    return {
      sales,
      total,
      page,
      limit,
      totalPages,
    };
  }

  @Get('summary')
  @ApiOperation({
    summary: 'Get sales summary for the current tenant',
    description: 'Retrieves key sales metrics and statistics',
  })
  @ApiResponse({
    status: HttpStatus.OK,
    description: 'Sales summary retrieved successfully',
    type: SalesSummaryDto,
  })
  async getSummary(@CurrentUser() user: AuthenticatedUser): Promise<SalesSummaryDto> {
    this.logger.log(`Fetching sales summary for tenant ${user.tenantId}`);
    
    // This would be implemented in the service
    // For now, return a placeholder implementation
    const today = new Date();
    const startOfDay = new Date(today.getFullYear(), today.getMonth(), today.getDate());
    
    const { sales: allSales } = await this.salesService.findAll(user, 1, 1000);
    const { sales: todaySales } = await this.salesService.findAll(user, 1, 1000, undefined, startOfDay);

    const totalRevenue = allSales.reduce((sum, sale) => sum + sale.total, 0);
    const todayRevenue = todaySales.reduce((sum, sale) => sum + sale.total, 0);
    const averageSaleAmount = allSales.length > 0 ? totalRevenue / allSales.length : 0;

    return {
      totalSales: allSales.length,
      totalRevenue,
      averageSaleAmount,
      todaySales: todaySales.length,
      todayRevenue,
    };
  }

  @Get(':id')
  @ApiOperation({
    summary: 'Get a specific sale by ID',
    description: 'Retrieves detailed information about a specific sale',
  })
  @ApiParam({
    name: 'id',
    description: 'Sale ID',
    type: 'string',
    format: 'uuid',
    example: 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11',
  })
  @ApiResponse({
    status: HttpStatus.OK,
    description: 'Sale retrieved successfully',
    type: SaleResponseDto,
  })
  @ApiResponse({
    status: HttpStatus.NOT_FOUND,
    description: 'Sale not found',
    schema: {
      type: 'object',
      properties: {
        statusCode: { type: 'number', example: 404 },
        message: { type: 'string', example: 'Sale not found' },
        error: { type: 'string', example: 'Not Found' },
      },
    },
  })
  async findOne(
    @Param('id', new ParseUUIDPipe({ version: '4' })) id: string,
    @CurrentUser() user: AuthenticatedUser,
  ): Promise<SaleResponseDto> {
    this.logger.log(`Fetching sale ${id} for tenant ${user.tenantId}`);
    
    return this.salesService.findOne(id, user);
  }

  // Additional endpoints that could be implemented

  @Get('by-number/:saleNumber')
  @ApiOperation({
    summary: 'Get a sale by sale number',
    description: 'Retrieves a sale using its human-readable sale number',
  })
  @ApiParam({
    name: 'saleNumber',
    description: 'Sale number (e.g., 20240115-0001)',
    type: 'string',
    example: '20240115-0001',
  })
  async findBySaleNumber(
    @Param('saleNumber') saleNumber: string,
    @CurrentUser() user: AuthenticatedUser,
  ): Promise<SaleResponseDto> {
    this.logger.log(`Fetching sale by number ${saleNumber} for tenant ${user.tenantId}`);
    
    // This would need to be implemented in the service
    throw new Error('Not implemented yet');
  }

  @Get('daily/:date')
  @ApiOperation({
    summary: 'Get sales for a specific date',
    description: 'Retrieves all sales for a specific date',
  })
  @ApiParam({
    name: 'date',
    description: 'Date in YYYY-MM-DD format',
    type: 'string',
    example: '2024-01-15',
  })
  async getDailySales(
    @Param('date') dateStr: string,
    @CurrentUser() user: AuthenticatedUser,
  ) {
    this.logger.log(`Fetching daily sales for ${dateStr} in tenant ${user.tenantId}`);
    
    const date = new Date(dateStr);
    if (isNaN(date.getTime())) {
      throw new Error('Invalid date format. Use YYYY-MM-DD');
    }

    const startOfDay = new Date(date.getFullYear(), date.getMonth(), date.getDate());
    const endOfDay = new Date(date.getFullYear(), date.getMonth(), date.getDate() + 1);

    return this.salesService.findAll(user, 1, 1000, undefined, startOfDay, endOfDay);
  }
}