import {
  Controller,
  Get,
  Post,
  Patch,
  Delete,
  Body,
  Query,
  Param,
  UseGuards,
  Request,
  HttpStatus,
  HttpCode,
  UseInterceptors,
  UploadedFile,
  Sse,
  MessageEvent,
} from '@nestjs/common';
import { ModuleRef } from '@nestjs/core';
import { ProductsService } from './services/products.service';
import { SyncQueueService } from './services/sync-queue.service';
import { OrdersService } from './services/orders.service';
import { OrderEventsService } from './services/order-events.service';
import { DeliveryTrackingService } from './services/delivery-tracking.service';
import { WhatsAppService } from '../whatsapp/services/whatsapp.service';
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
import { SubscriptionGuard } from '../subscription/subscription.guard';
import { FileInterceptor } from '@nestjs/platform-express';
import { diskStorage } from 'multer';
import { extname } from 'path';
import { Observable } from 'rxjs';
import { map, filter } from 'rxjs/operators';
import { AuthenticatedRequest } from '../../common/interfaces/auth-request.interface';

@Controller('api')
@UseGuards(JwtAuthGuard, SubscriptionGuard)
export class CommerceController {
  constructor(
    private readonly productsService: ProductsService,
    private readonly syncQueueService: SyncQueueService,
    private readonly ordersService: OrdersService,
    private readonly orderEventsService: OrderEventsService,
    private readonly trackingService: DeliveryTrackingService,
    private readonly moduleRef: ModuleRef,
  ) {}

  // Products & Categories
  @Get('products')
  async getProducts(
    @Request() req: any,
    @Query('search') search?: string,
    @Query('categoryId') categoryId?: string,
  ) {
    const authReq = req as AuthenticatedRequest;
    return this.productsService.listProducts(
      authReq.user.id,
      search,
      categoryId,
    );
  }

  @Post('products')
  async createProduct(@Request() req: any, @Body() body: any) {
    const authReq = req as AuthenticatedRequest;
    return this.productsService.createProduct(authReq.user.id, body);
  }

  @Patch('products/:id')
  async updateProduct(
    @Request() req: any,
    @Param('id') id: string,
    @Body() body: any,
  ) {
    const authReq = req as AuthenticatedRequest;
    return this.productsService.updateProduct(authReq.user.id, id, body);
  }

  @Delete('products/:id')
  async deleteProduct(@Request() req: any, @Param('id') id: string) {
    const authReq = req as AuthenticatedRequest;
    return this.productsService.deleteProduct(authReq.user.id, id);
  }

  @Get('categories')
  async getCategories(@Request() req: any) {
    const authReq = req as AuthenticatedRequest;
    return this.productsService.listCategories(authReq.user.id);
  }

  @Post('categories')
  async createCategory(@Request() req: any, @Body() body: any) {
    const authReq = req as AuthenticatedRequest;
    return this.productsService.createCategory(authReq.user.id, body);
  }

  @Patch('categories/:id')
  async updateCategory(
    @Request() req: any,
    @Param('id') id: string,
    @Body() body: any,
  ) {
    const authReq = req as AuthenticatedRequest;
    return this.productsService.updateCategory(authReq.user.id, id, body);
  }

  @Delete('categories/:id')
  async deleteCategory(@Request() req: any, @Param('id') id: string) {
    const authReq = req as AuthenticatedRequest;
    return this.productsService.deleteCategory(authReq.user.id, id);
  }

  @Post('products/upload')
  @UseInterceptors(
    FileInterceptor('file', {
      storage: diskStorage({
        destination: './uploads',
        filename: (req, file, callback) => {
          const uniqueSuffix =
            Date.now() + '-' + Math.round(Math.random() * 1e9);
          callback(null, `${uniqueSuffix}${extname(file.originalname)}`);
        },
      }),
      fileFilter: (req, file, callback) => {
        if (!file.originalname.match(/\.(jpg|jpeg|png|gif|webp)$/)) {
          return callback(new Error('Only image files are allowed!'), false);
        }
        callback(null, true);
      },
    }),
  )
  uploadImage(@UploadedFile() file?: any) {
    if (!file) {
      return { success: false, message: 'No file uploaded' };
    }
    return { imageUrl: `/uploads/${file.filename}` };
  }

  @Post('products/sync')
  @HttpCode(HttpStatus.ACCEPTED)
  async syncProducts(@Request() req: any) {
    const authReq = req as AuthenticatedRequest;
    const syncLogId = await this.syncQueueService.triggerSync(
      authReq.user.id,
      'products',
    );
    return {
      success: true,
      syncLogId,
      message: 'Synchronization started in background',
    };
  }

  @Get('products/sync-logs')
  async getSyncLogs(@Request() req: any) {
    const authReq = req as AuthenticatedRequest;
    return this.syncQueueService.getSyncLogs(authReq.user.id);
  }

  // Orders & Payments
  @Get('orders')
  async getOrders(@Request() req: any) {
    const authReq = req as AuthenticatedRequest;
    return this.ordersService.listOrders(authReq.user.id);
  }

  @Get('orders/:id')
  async getOrder(@Param('id') id: string) {
    return this.ordersService.getOrder(id);
  }

  @Patch('orders/:id/status')
  async updateOrderStatus(
    @Request() req: any,
    @Param('id') id: string,
    @Body() body: { status: string },
  ) {
    const authReq = req as AuthenticatedRequest;
    return this.ordersService.updateOrderStatus(
      authReq.user.id,
      id,
      body.status,
    );
  }

  @Get('customers')
  async getCustomers(@Request() req: any) {
    const authReq = req as AuthenticatedRequest;
    return this.ordersService.listCustomers(authReq.user.id);
  }

  @Sse('orders/events')
  sendOrderEvents(@Request() req: any): Observable<MessageEvent> {
    const authReq = req as AuthenticatedRequest;
    const businessId = authReq.user.id;
    return this.orderEventsService.getOrderUpdates().pipe(
      filter((event) => event.businessId === businessId),
      map((event) => ({
        data: {
          type: event.type,
          orderId: event.orderId,
          orderNumber: event.orderNumber,
          status: event.status,
        },
      })),
    );
  }

  // ── Delivery Tracking ────────────────────────────────────────────────────
  @Get('orders/:id/tracking')
  async getOrderTracking(@Param('id') id: string) {
    return this.trackingService.getTracking(id);
  }

  @Post('orders/:id/tracking')
  async createOrderTracking(
    @Request() req: any,
    @Param('id') id: string,
    @Body() body: any,
  ) {
    const authReq = req as AuthenticatedRequest;
    return this.handleTrackingUpsert(authReq, id, body);
  }

  @Patch('orders/:id/tracking')
  async updateOrderTracking(
    @Request() req: any,
    @Param('id') id: string,
    @Body() body: any,
  ) {
    const authReq = req as AuthenticatedRequest;
    return this.handleTrackingUpsert(authReq, id, body);
  }

  private async handleTrackingUpsert(
    req: AuthenticatedRequest,
    orderId: string,
    body: {
      driverName?: string;
      driverPhone?: string;
      status?: string;
      currentLat?: number;
      currentLng?: number;
      etaMinutes?: number;
      notes?: string;
      notifyCustomer?: boolean;
    },
  ) {
    const { notifyCustomer, ...trackingData } = body;
    const tracking = await this.trackingService.upsertTracking(
      orderId,
      trackingData,
    );

    if (notifyCustomer || trackingData.status === 'DISPATCHED') {
      try {
        const order = await this.ordersService.getOrder(orderId);
        if (order?.customerPhone) {
          const frontendUrl =
            process.env.NEXT_PUBLIC_FRONTEND_URL ||
            process.env.FRONTEND_URL ||
            'http://localhost:3000';
          const trackingUrl = `${frontendUrl}/track/${orderId}`;

          const statusEmoji: Record<string, string> = {
            PREPARING: '📦',
            DISPATCHED: '🚚',
            IN_TRANSIT: '🛣️',
            DELIVERED: '✅',
          };
          const statusLabel: Record<string, string> = {
            PREPARING: 'being prepared',
            DISPATCHED: 'on its way',
            IN_TRANSIT: 'in transit',
            DELIVERED: 'delivered',
          };

          const emoji =
            statusEmoji[trackingData.status || 'DISPATCHED'] || '🚚';
          const label =
            statusLabel[trackingData.status || 'DISPATCHED'] || 'on its way';
          const driverLine = tracking.driverName
            ? `\n🧑 Driver: *${tracking.driverName}*${tracking.driverPhone ? ` (${tracking.driverPhone})` : ''}`
            : '';
          const etaLine = tracking.etaMinutes
            ? `\n⏱ ETA: *${tracking.etaMinutes} minutes*`
            : '';

          // Lazy-resolve WhatsAppService to avoid circular module dependency
          const whatsappService = this.moduleRef.get(WhatsAppService, {
            strict: false,
          });
          await whatsappService.sendMessage(
            order.customerPhone,
            `${emoji} *Order Update — #${order.orderNumber}*\n\nYour order is *${label}!*${driverLine}${etaLine}\n\n📍 Track your delivery:\n${trackingUrl}`,
            req.user.id,
          );

          await this.trackingService.upsertTracking(orderId, {
            notifiedAt: new Date(),
          });
        }
      } catch (notifyErr) {
        console.warn(
          'Failed to send WhatsApp tracking notification:',
          notifyErr,
        );
      }
    }

    return tracking;
  }
}
