// src/chat/chat.controller.ts
import {
  Controller, Get, Post, Delete, Body,
  Param, Query, Request, ParseIntPipe,
  UseInterceptors, UploadedFile, BadRequestException,
} from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { diskStorage } from 'multer';
import { extname } from 'path';
import { existsSync, mkdirSync } from 'fs';
import { ChatService } from './chat.service';
import { ChatGateway } from './chat.gateway';
import { PushService } from './push.service';
import { CreateRoomDto } from './dto/chat.dto';

// Helper to get userId from JWT request
function getUserId(req: any): number {
  return Number(req.user?.sub ?? req.user?.id ?? req.user?.userId ?? 0);
}

// Ensure upload directory exists
const UPLOAD_DIR = './uploads/chat';
if (!existsSync(UPLOAD_DIR)) {
  mkdirSync(UPLOAD_DIR, { recursive: true });
}

@Controller('chat')
export class ChatController {
  constructor(
    private readonly chatService: ChatService,
    private readonly chatGateway: ChatGateway,
    private readonly pushService: PushService,
  ) {}

  // ── GET /chat/rooms — all rooms for current user ──────────────────────────
  @Get('rooms')
  async getRooms(@Request() req) {
    const userId = getUserId(req);
    return this.chatService.getRoomsForUser(userId);
  }

  // ── POST /chat/rooms — create a group room ────────────────────────────────
  @Post('rooms')
  async createRoom(@Body() dto: CreateRoomDto, @Request() req) {
    const userId = getUserId(req);
    if (!dto.memberIds.includes(userId)) {
      dto.memberIds.push(userId);
    }
    return this.chatService.createRoom(dto);
  }

  // ── POST /chat/rooms/direct/:targetUserId — get or create direct room ─────
  @Post('rooms/direct/:targetUserId')
  async getOrCreateDirect(
    @Param('targetUserId', ParseIntPipe) targetUserId: number,
    @Request() req,
  ) {
    const userId = getUserId(req);
    return this.chatService.getOrCreateDirectRoom(userId, targetUserId);
  }

  // ── GET /chat/rooms/:roomId — single room details ─────────────────────────
  @Get('rooms/:roomId')
  async getRoom(@Param('roomId', ParseIntPipe) roomId: number) {
    return this.chatService.getRoom(roomId);
  }

  // ── GET /chat/rooms/:roomId/messages — message history ───────────────────
  @Get('rooms/:roomId/messages')
  async getMessages(
    @Param('roomId', ParseIntPipe) roomId: number,
    @Query('page') page = '1',
    @Query('limit') limit = '50',
    @Request() req,
  ) {
    const userId = getUserId(req);
    return this.chatService.getMessages(roomId, userId, Number(page), Number(limit));
  }

  // ── GET /chat/rooms/:roomId/members — who is in the room ─────────────────
  @Get('rooms/:roomId/members')
  async getMembers(@Param('roomId', ParseIntPipe) roomId: number) {
    return this.chatService.getRoomMembers(roomId);
  }

  // ── GET /chat/unread — total unread count across all rooms ────────────────
  @Get('unread')
  async getUnreadCount(@Request() req) {
    const userId = getUserId(req);
    const count = await this.chatService.getTotalUnread(userId);
    return { count };
  }

  // ── GET /chat/users — all users to start a new chat ──────────────────────
  @Get('users')
  async getAllUsers(@Request() req) {
    const userId = getUserId(req);
    return this.chatService.getAllUsers(userId);
  }

  // ── GET /chat/online — which users are currently online ──────────────────
  @Get('online')
  async getOnlineStatus(@Query('userIds') userIds: string) {
    const ids = userIds.split(',').map(Number).filter(Boolean);
    const result: Record<number, boolean> = {};
    for (const id of ids) {
      result[id] = this.chatGateway.isOnline(id);
    }
    return result;
  }

  // ╔═══════════════════════════════════════════════════════════════════════╗
  // ║  FILE & IMAGE UPLOAD                                                 ║
  // ╚═══════════════════════════════════════════════════════════════════════╝

  // ── POST /chat/upload — upload file or image, returns URL ────────────────
  @Post('upload')
  @UseInterceptors(
    FileInterceptor('file', {
      storage: diskStorage({
        destination: UPLOAD_DIR,
        filename: (_req, file, cb) => {
          const safe = `${Date.now()}-${Math.round(Math.random() * 1e9)}${extname(file.originalname)}`;
          cb(null, safe);
        },
      }),
      limits: { fileSize: 10 * 1024 * 1024 }, // 10 MB
      fileFilter: (_req, file, cb) => {
        const allowed = /\.(jpg|jpeg|png|gif|webp|pdf|doc|docx|xls|xlsx|ppt|pptx|txt|zip|rar)$/i;
        if (allowed.test(file.originalname)) {
          cb(null, true);
        } else {
          cb(new BadRequestException('File type not allowed'), false);
        }
      },
    }),
  )
  async uploadFile(@UploadedFile() file: any, @Request() req) {
    if (!file) throw new BadRequestException('No file uploaded');
    const userId = getUserId(req);
    if (!userId) throw new BadRequestException('Not authenticated');

    const isImage = /\.(jpg|jpeg|png|gif|webp)$/i.test(file.originalname);
    return {
      success:   true,
      file_url:  `/uploads/chat/${file.filename}`,
      file_name: file.originalname,
      type:      isImage ? 'image' : 'file',
      size:      file.size,
    };
  }

  // ╔═══════════════════════════════════════════════════════════════════════╗
  // ║  WEB PUSH NOTIFICATIONS                                              ║
  // ╚═══════════════════════════════════════════════════════════════════════╝

  // ── POST /chat/push/subscribe — register a browser for push ─────────────
  @Post('push/subscribe')
  async subscribePush(
    @Request() req,
    @Body() body: { endpoint: string; keys: { p256dh: string; auth: string } },
  ) {
    const userId = getUserId(req);
    if (!userId) {
      return { success: false, error: 'Not authenticated' };
    }
    if (!body?.endpoint || !body?.keys?.p256dh || !body?.keys?.auth) {
      return { success: false, error: 'Invalid subscription payload' };
    }
    await this.pushService.subscribe(userId, body.endpoint, body.keys);
    return { success: true };
  }

  // ── DELETE /chat/push/subscribe — remove a subscription ─────────────────
  @Delete('push/subscribe')
  async unsubscribePush(@Body() body: { endpoint: string }) {
    if (!body?.endpoint) {
      return { success: false, error: 'Endpoint required' };
    }
    await this.pushService.unsubscribe(body.endpoint);
    return { success: true };
  }
}