import {
  Body,
  Controller,
  Get,
  Param,
  ParseIntPipe,
  Patch,
  Post,
  Put,
  Query,
  Req,
  UploadedFiles,
  UseGuards,
  UseInterceptors,
} from "@nestjs/common"
import {
  ApiBearerAuth,
  ApiBody,
  ApiConsumes,
  ApiOperation,
  ApiParam,
  ApiQuery,
  ApiResponse,
  ApiTags,
} from "@nestjs/swagger"
import { AuthGuardMiddleware } from "src/middleware/auth-guard.middleware"
import { TeamMemberService } from "./team-member.service"
import { FindAllDriverDto } from "../dto/drivers/find-all-drivers.dto"
import { VehicleHistoryQueryDto } from "../dto/drivers/driver-vehicle-history.dto"
import { DeclineTripDto } from "../dto/drivers/decline-trip.dto"
import { FileFieldsInterceptor } from "@nestjs/platform-express"
import { teamMemberFileUploadConfig } from "src/common/file-upload/team-member-upload.config"
import { AcceptTripDto } from "../dto/drivers/accept-trip.dto"
import { GetTripsQueryDto } from "../dto/trip/get-trips.dto"
import { StartTripDto } from "../dto/drivers/start-trip.dto"
import { TripReachedDto } from "../dto/drivers/trip-reached.dto"
import { SendMessageDto } from "../../chat/dto/send-message.dto"
import { ChatHistoryDto } from "../../chat/dto/chat-history.dto"
import {
  ChatMessageResponseDto,
  ChatHistoryResponseDto,
  MarkMessagesReadResponseDto,
} from "../../chat/dto/chat-message-response.dto"
import { CreateTeamMemberDto } from "../dto/team-members/create-team-member.dto"
import { UpdateTeamMemberDto } from "../dto/team-members/update-team-member.dto"

@ApiTags("Drivers")
@UseGuards(AuthGuardMiddleware)
@ApiBearerAuth("access-token")
@Controller("drivers")
export class DriverController {
  constructor(private readonly driverService: TeamMemberService) {}

  @Post("create")
  @UseInterceptors(
    FileFieldsInterceptor(
      [
        { name: "profile_photo", maxCount: 1 },
        { name: "document_files", maxCount: 5 },
      ],
      teamMemberFileUploadConfig,
    ),
  )
  @ApiConsumes("multipart/form-data")
  @ApiBody({ type: CreateTeamMemberDto })
  async createTeamMember(
    @Body() createTeamMemberDto: CreateTeamMemberDto,
    @UploadedFiles()
    files: {
      profile_photo?: Express.Multer.File[]
      document_files?: Express.Multer.File[]
    },
  ) {
    const profilePhoto = files.profile_photo?.[0]
    const documentFiles = files.document_files

    return await this.driverService.createTeamMember(
      createTeamMemberDto,
      profilePhoto,
      documentFiles,
    )
  }

  @Get()
  @ApiOperation({ summary: "Get drivers grouped by dispatchers" })
  async getDispatchersWiseDrivers(@Query() params: FindAllDriverDto) {
    return this.driverService.getDispatchersWiseDrivers(params)
  }

  @Put("update/:id")
  @UseInterceptors(
    FileFieldsInterceptor(
      [
        { name: "profile_photo", maxCount: 1 },
        { name: "document_files", maxCount: 10 },
      ],
      teamMemberFileUploadConfig,
    ),
  )
  @ApiConsumes("multipart/form-data")
  async update(
    @Param("id") id: number,
    @Body() updateData: UpdateTeamMemberDto,
    @UploadedFiles()
    files: {
      profile_photo?: Express.Multer.File[]
      document_files?: Express.Multer.File[]
    },
  ) {
    const profilePhoto = files.profile_photo?.[0]
    const documentFiles = files.document_files

    return await this.driverService.updateTeamMember(
      id,
      updateData,
      profilePhoto,
      documentFiles,
    )
  }

  @Get("vehicle/:id")
  @ApiOperation({ summary: "Get vehicle history for a driver" })
  async assignFleetsToTrip(
    @Req() request: any,
    @Param("id") driver_id: number,
    @Query() vehicleHistoryQueryDto: VehicleHistoryQueryDto,
  ) {
    return this.driverService.getDriverAssignVehicle(
      driver_id,
      vehicleHistoryQueryDto,
    )
  }

  @Get("profile/:id")
  @ApiOperation({ summary: "Get driver profile details" })
  async getDriverProfileDeatails(@Param("id") driverId: number) {
    return this.driverService.getDriverProfileDeatails(driverId)
  }

  @Patch(":id/driving-licence")
  @UseInterceptors(
    FileFieldsInterceptor(
      [{ name: "document_files", maxCount: 1 }],
      teamMemberFileUploadConfig,
    ),
  )
  @ApiConsumes("multipart/form-data")
  @ApiBody({
    schema: {
      type: "object",
      properties: {
        document_number: { type: "string" },
        expiry_date: { type: "string", format: "date" },
        document_status: { type: "string" },
        document_files: {
          type: "string",
          format: "binary",
        },
      },
      required: ["document_number"],
    },
  })
  async updateDrivingLicence(
    @Param("id", ParseIntPipe) id: number,
    @Body()
    body: {
      document_number: string
      expiry_date?: string
      document_status?: string
    },
    @UploadedFiles()
    files: {
      document_files?: Express.Multer.File[]
    },
  ) {
    const documentFile = files.document_files?.[0]
    return this.driverService.addDriverLicenceForDriver(id, body, documentFile)
  }

  @Get("trips/:id")
  @ApiOperation({ summary: "Get driver's trips" })
  async trips(@Param("id") id: number, @Query() query: GetTripsQueryDto) {
    return this.driverService.getDriverTrips(
      id,
      query.type,
      { page: query.page, limit: query.limit },
      query.pastTripType,
      query.fromDate,
    )
  }

  @Post("trip/decline")
  @ApiOperation({ summary: "Decline a trip" })
  async declineTrip(@Body() declineTripDto: DeclineTripDto) {
    return this.driverService.declineTrip(
      declineTripDto.trip_id,
      declineTripDto.driver_id,
    )
  }

  @Post("trip/accept")
  @ApiOperation({ summary: "Accept a trip" })
  async acceptTrip(@Body() acceptTripDto: AcceptTripDto) {
    return this.driverService.acceptTrip(
      acceptTripDto.trip_id,
      acceptTripDto.driver_id,
      acceptTripDto.fleet_id,
    )
  }

  @Post("trip/reached")
  @ApiOperation({ summary: "Trip reached at the specified stop" })
  async cancelTrip(@Body() tripReachedDto: TripReachedDto) {
    return this.driverService.reachedAtStop(
      tripReachedDto.trip_id,
      tripReachedDto.stop_id,
    )
  }

  @Post("trip/complete")
  @ApiOperation({ summary: "Complete a trip" })
  async completeTrip(@Body() acceptTripDto: AcceptTripDto) {
    return this.driverService.completeTrip(
      acceptTripDto.trip_id,
      acceptTripDto.driver_id,
    )
  }

  @Post("trip/start")
  @ApiOperation({ summary: "Start a trip" })
  async startTrip(@Body() startTripDto: StartTripDto) {
    return this.driverService.startTrip(
      startTripDto.trip_id,
      startTripDto.driver_id,
      startTripDto.otp,
    )
  }

  @Get("/count/trip-cancelled/:driver_id")
  @ApiOperation({ summary: "Get cancelled trips count" })
  @ApiParam({
    name: "driver_id",
    type: Number,
    description: "Driver ID for which cancelled trips will be counted",
    example: 42,
  })
  @ApiQuery({
    name: "start_timestamp",
    type: String,
    required: false,
    description:
      "Filter start timestamp (ISO8601). Example: 2025-08-01T00:00:00Z",
    example: "2025-08-01T00:00:00Z",
  })
  @ApiQuery({
    name: "end_timestamp",
    type: String,
    required: false,
    description:
      "Filter end timestamp (ISO8601). Example: 2025-08-29T23:59:59Z",
    example: "2025-08-29T23:59:59Z",
  })
  async getCancelledTripsCount(
    @Param("driver_id") driver_id: number,
    @Query("start_timestamp") start_timestamp: string,
    @Query("end_timestamp") end_timestamp: string,
  ) {
    return this.driverService.getCancelledTripsCount(
      driver_id,
      start_timestamp,
      end_timestamp,
    )
  }

  @Get("/count/ratings/:driver_id")
  @ApiOperation({ summary: "Get ratings count" })
  @ApiParam({
    name: "driver_id",
    type: Number,
    description: "Driver ID for which trips ratings will be counted",
    example: 42,
  })
  @ApiQuery({
    name: "start_timestamp",
    type: String,
    required: false,
    description:
      "Filter start timestamp (ISO8601). Example: 2025-08-01T00:00:00Z",
    example: "2025-08-01T00:00:00Z",
  })
  @ApiQuery({
    name: "end_timestamp",
    type: String,
    required: false,
    description:
      "Filter end timestamp (ISO8601). Example: 2025-08-29T23:59:59Z",
    example: "2025-08-29T23:59:59Z",
  })
  async getRatingsCount(@Param("driver_id") driver_id: number) {
    return this.driverService.getRating(driver_id)
  }

  @ApiOperation({
    summary: "Get driver dispatcher",
    description: "Get the dispatcher assigned to the current driver",
  })
  @ApiResponse({
    status: 200,
    description: "Dispatcher details retrieved successfully",
    schema: {
      type: "object",
      properties: {
        id: { type: "number", example: 123 },
        first_name: { type: "string", example: "John" },
        last_name: { type: "string", example: "Doe" },
        phone_number: { type: "string", example: "+1234567890" },
        profile_photo: { type: "string", example: "uploads/profile.jpg" },
      },
    },
  })
  @Get("dispatcher")
  async getDriverDispatcher(@Req() request: any) {
    return await this.driverService.getDriverDispatcher(request.user.id)
  }

  @ApiOperation({
    summary: "Send message to dispatcher",
    description:
      "Allows driver to send chat messages to their assigned dispatcher",
  })
  @ApiBody({ type: SendMessageDto })
  @ApiResponse({
    status: 200,
    description: "Message sent successfully",
    type: ChatMessageResponseDto,
  })
  @ApiResponse({
    status: 400,
    description: "Bad request - validation error",
  })
  @ApiResponse({
    status: 404,
    description: "Dispatcher not found",
  })
  @Post("send-message")
  async sendMessageToDispatcher(@Body() sendMessageDto: SendMessageDto) {
    return await this.driverService.sendMessageToDispatcher(sendMessageDto)
  }

  @ApiOperation({
    summary: "Get chat history",
    description: "Retrieve chat message history for a specific chat room",
  })
  @ApiBody({ type: ChatHistoryDto })
  @ApiResponse({
    status: 200,
    description: "Chat history retrieved successfully",
    type: ChatHistoryResponseDto,
  })
  @ApiResponse({
    status: 400,
    description: "Bad request - validation error",
  })
  @Post("chat-history")
  async getChatHistory(@Body() chatHistoryDto: ChatHistoryDto) {
    return await this.driverService.getChatHistory(chatHistoryDto)
  }

  @ApiOperation({
    summary: "Mark messages as read",
    description: "Mark chat messages as read for a specific chat room",
  })
  @ApiBody({
    schema: {
      type: "object",
      properties: {
        dispatcher_id: { type: "number", example: 123 },
        chat_room_id: { type: "number", example: 456 },
      },
      required: ["dispatcher_id", "chat_room_id"],
    },
  })
  @ApiResponse({
    status: 200,
    description: "Messages marked as read successfully",
    type: MarkMessagesReadResponseDto,
  })
  @ApiResponse({
    status: 400,
    description: "Bad request - validation error",
  })
  @Post("mark-messages-read")
  async markMessagesAsRead(
    @Body() data: { dispatcher_id: number; chat_room_id: number },
  ) {
    return await this.driverService.markMessagesAsRead(
      data.dispatcher_id,
      data.chat_room_id,
    )
  }
}
