import {
  Controller,
  Get,
  Post,
  Body,
  Put,
  Param,
  Delete,
  Query,
  Req,
  UseGuards,
  Patch,
  UseInterceptors,
  UploadedFiles,
} from "@nestjs/common"
import { FileFieldsInterceptor } from "@nestjs/platform-express"
import { ApiConsumes, ApiBody } from "@nestjs/swagger"
import { CreateEmployeeDto } from "./dto/create-employee.dto"
import { UpdateEmployeeDto } from "./dto/update-employee.dto"
import { AssignProjectsDto } from "./dto/assign-projects.dto"
import { UpdateLeaveBalancesDto } from "./dto/update-leave-balances.dto"
import { ApiBearerAuth, ApiTags, ApiQuery } from "@nestjs/swagger"
import { AuthGuardMiddleware } from "../../middleware/auth-guard.middleware"
import { UpdateSalaryHistoryDto } from "./dto/update-salary-dto"
import { employeeUploadsConfig } from "../../common/file-upload/employee-uploads.config"
import { EmployeesService } from "./employees.service"
import { CreateEmployeeTechnologyDto } from "./dto/create-employee-technology.dto"
import { UpdateEmployeeTechnologyDto } from "./dto/update-employee-technology.dto"
import { AssignTechnologyEmployeesDto } from "./dto/assign-technology-employees.dto"
import { FilterEmployeeTechnologyDto } from "./dto/filter-employee-technology.dto"

const employeeFileFields = [
  { name: "resume", maxCount: 1 },
  { name: "offer_letter", maxCount: 1 },
  { name: "appointment_letter", maxCount: 1 },
  { name: "id_proof", maxCount: 1 },
  { name: "address_proof", maxCount: 1 },
  { name: "education_certificates", maxCount: 1 },
]

@Controller("employees")
@ApiTags("Employees")
@UseGuards(AuthGuardMiddleware)
@ApiBearerAuth("access-token")
export class EmployeesController {
  constructor(private readonly employeesService: EmployeesService) {}

  @Post()
  @ApiConsumes("multipart/form-data")
  @ApiBody({
    description: "Create employee",
    schema: {
      type: "object",
      required: ["first_name", "employee_type", "role_id"],
      properties: {
        // ── Core employee fields ──────────────────────────────────────────────
        first_name: {
          type: "string",
          description: "First name of the employee",
        },
        last_name: { type: "string", description: "Last name of the employee" },
        email: {
          type: "string",
          description: "Official email of the employee",
        },
        contact_no: {
          type: "string",
          description: "Contact number of the employee",
        },
        employee_type: {
          type: "string",
          enum: ["employee", "trainee", "contract"],
          description: "Type of employee",
        },
        employee_number: {
          type: "string",
          description: "Employee number assigned by HR",
        },
        role_id: { type: "integer", description: "Role ID" },
        department_id: { type: "integer", description: "Department ID" },
        sub_department_id: {
          type: "integer",
          description: "Sub Department ID",
        },
        team_lead_id: {
          type: "integer",
          description: "Reporting manager (Employee ID)",
        },
        gross_salary: { type: "number", description: "Gross salary" },
        stipend: {
          type: "number",
          description: "Stipend amount (for trainees)",
        },
        joining_date: {
          type: "string",
          format: "date",
          description: "Date of joining",
        },
        work_location: {
          type: "string",
          enum: ["WFO", "WFH", "Hybrid"],
          description: "Work location",
        },
        probation_period: {
          type: "integer",
          description: "Probation period in days",
        },
        notice_period: {
          type: "integer",
          description: "Notice period in days",
        },
        // ── Personal details ──────────────────────────────────────────────────
        gender: {
          type: "string",
          enum: ["Male", "Female", "Other"],
          description: "Gender",
        },
        date_of_birth: {
          type: "string",
          format: "date",
          description: "Date of birth",
        },
        marital_status: {
          type: "string",
          enum: ["Single", "Married", "Divorced", "Widowed"],
          description: "Marital status",
        },
        blood_group: { type: "string", description: "Blood group" },
        alternate_mobile_number: {
          type: "string",
          description: "Alternate mobile number",
        },
        personal_email: { type: "string", description: "Personal email ID" },
        parents_name: { type: "string", description: "Parents name" },
        parents_contact_number: {
          type: "string",
          description: "Parents contact number",
        },
        emergency_contact_name: {
          type: "string",
          description: "Emergency contact name",
        },
        emergency_contact_relationship: {
          type: "string",
          description: "Relationship with emergency contact",
        },
        emergency_contact_number: {
          type: "string",
          description: "Emergency contact number",
        },
        // ── Address details ───────────────────────────────────────────────────
        address: { type: "string", description: "Current address" },
        permanent_address: { type: "string", description: "Permanent address" },
        pincode: { type: "string", description: "Pincode" },
        native_place: { type: "string", description: "Native place" },
        // ── Experience details ────────────────────────────────────────────────
        total_work_experience_years: {
          type: "number",
          description: "Total work experience in years",
        },
        previous_company_name: {
          type: "string",
          description: "Previous company name",
        },
        previous_designation: {
          type: "string",
          description: "Previous designation",
        },
        last_salary: { type: "number", description: "Last drawn salary" },
        education_qualification: {
          type: "string",
          description: "Education qualification",
        },
        // ── Bank details ──────────────────────────────────────────────────────
        bank_name: { type: "string", description: "Bank name" },
        account_number: { type: "string", description: "Bank account number" },
        ifsc_code: { type: "string", description: "IFSC code" },
        account_holder_name: {
          type: "string",
          description: "Account holder name",
        },
        // ── Identity details ──────────────────────────────────────────────────
        aadhar_card: { type: "string", description: "Aadhaar card number" },
        pan_card_number: { type: "string", description: "PAN card number" },
        uan: { type: "string", description: "UAN (Universal Account Number)" },
        // ── Documents ─────────────────────────────────────────────────────────
        resume: {
          type: "string",
          format: "binary",
          description: "Resume file (PDF)",
        },
        offer_letter: {
          type: "string",
          format: "binary",
          description: "Offer letter document (PDF/image)",
        },
        appointment_letter: {
          type: "string",
          format: "binary",
          description: "Appointment letter document (PDF/image)",
        },
        id_proof: {
          type: "string",
          format: "binary",
          description: "ID proof document (PDF/image)",
        },
        address_proof: {
          type: "string",
          format: "binary",
          description: "Address proof document (PDF/image)",
        },
        education_certificates: {
          type: "string",
          format: "binary",
          description: "Education certificates (PDF/image)",
        },
        // ── Salary ────────────────────────────────────────────────────────────
        regime_type: {
          type: "string",
          enum: ["old", "new"],
          description: "Tax regime type",
        },
        salary_settings: {
          type: "string",
          description: "JSON array of salary settings",
        },
      },
    },
  })
  @UseInterceptors(
    FileFieldsInterceptor(employeeFileFields, employeeUploadsConfig),
  )
  create(
    @Body() createEmployeeDto: CreateEmployeeDto,
    @Req() request: Request,
    @UploadedFiles() files: Record<string, Express.Multer.File[]>,
  ) {
    return this.employeesService.create(
      createEmployeeDto,
      request.headers["authorization"],
      files,
    )
  }

  @Get()
  findAll(@Query() query: any, @Req() request: Request) {
    return this.employeesService.findAll(
      query,
      request.headers["authorization"],
    )
  }

  @Get("my-leave-balances")
  getMyLeaveBalances(@Req() request: Request, @Query() query: any = {}) {
    return this.employeesService.getMyLeaveBalances(
      request.headers["authorization"],
      query,
    )
  }

  @Put("update-leave-balances")
  @ApiQuery({
    name: "employee_id",
    description: "Employee ID for whom to update leave balances",
    required: true,
    type: Number,
    example: 1,
  })
  @ApiBody({
    description: "Update employee leave balances total allocated days",
    type: UpdateLeaveBalancesDto,
  })
  async updateLeaveBalances(
    @Body() updateLeaveBalancesDto: UpdateLeaveBalancesDto,
    @Query("employee_id") employee_id: number,
    @Req() request: Request,
  ) {
    return this.employeesService.updateLeaveBalances(
      updateLeaveBalancesDto,
      employee_id,
      request.headers["authorization"],
    )
  }

  @Get("technologies")
  findAllTechnologies(
    @Query() query: FilterEmployeeTechnologyDto,
    @Req() request: Request,
  ) {
    return this.employeesService.findAllTechnologies(
      query,
      request.headers["authorization"],
    )
  }

  @Post("technologies")
  createTechnology(
    @Body() createDto: CreateEmployeeTechnologyDto,
    @Req() request: Request,
  ) {
    return this.employeesService.createTechnology(
      createDto,
      request.headers["authorization"],
    )
  }

  @Put("technologies/:id")
  updateTechnology(
    @Param("id") id: string,
    @Body() updateDto: UpdateEmployeeTechnologyDto,
    @Req() request: Request,
  ) {
    return this.employeesService.updateTechnology(
      +id,
      updateDto,
      request.headers["authorization"],
    )
  }

  @Post("technologies/assign-employees")
  assignTechnologyEmployees(
    @Body() assignDto: AssignTechnologyEmployeesDto,
    @Req() request: Request,
  ) {
    return this.employeesService.assignTechnologyEmployees(
      assignDto,
      request.headers["authorization"],
    )
  }

  @Get(":id")
  findOne(@Param("id") id: string) {
    return this.employeesService.findOne(+id)
  }

  @Put(":id")
  @ApiConsumes("multipart/form-data")
  @ApiBody({
    description: "Update employee",
    schema: {
      type: "object",
      properties: {
        // ── Core employee fields ──────────────────────────────────────────────
        first_name: {
          type: "string",
          description: "First name of the employee",
        },
        last_name: { type: "string", description: "Last name of the employee" },
        email: {
          type: "string",
          description: "Official email of the employee",
        },
        contact_no: {
          type: "string",
          description: "Contact number of the employee",
        },
        employee_type: {
          type: "string",
          enum: ["employee", "trainee", "contract"],
          description: "Type of employee",
        },
        employee_number: {
          type: "string",
          description: "Employee number assigned by HR",
        },
        role_id: { type: "integer", description: "Role ID" },
        department_id: { type: "integer", description: "Department ID" },
        sub_department_id: {
          type: "integer",
          description: "Sub Department ID",
        },
        team_lead_id: {
          type: "integer",
          description: "Reporting manager (Employee ID)",
        },
        gross_salary: { type: "number", description: "Gross salary" },
        stipend: { type: "number", description: "Stipend amount" },
        joining_date: {
          type: "string",
          format: "date",
          description: "Date of joining",
        },
        work_location: {
          type: "string",
          enum: ["WFO", "WFH", "Hybrid"],
          description: "Work location",
        },
        probation_period: {
          type: "integer",
          description: "Probation period in days",
        },
        notice_period: {
          type: "integer",
          description: "Notice period in days",
        },
        // ── Personal details ──────────────────────────────────────────────────
        gender: {
          type: "string",
          enum: ["Male", "Female", "Other"],
          description: "Gender",
        },
        date_of_birth: {
          type: "string",
          format: "date",
          description: "Date of birth",
        },
        marital_status: {
          type: "string",
          enum: ["Single", "Married", "Divorced", "Widowed"],
          description: "Marital status",
        },
        blood_group: { type: "string", description: "Blood group" },
        alternate_mobile_number: {
          type: "string",
          description: "Alternate mobile number",
        },
        personal_email: { type: "string", description: "Personal email ID" },
        parents_name: { type: "string", description: "Parents name" },
        parents_contact_number: {
          type: "string",
          description: "Parents contact number",
        },
        emergency_contact_name: {
          type: "string",
          description: "Emergency contact name",
        },
        emergency_contact_relationship: {
          type: "string",
          description: "Relationship with emergency contact",
        },
        emergency_contact_number: {
          type: "string",
          description: "Emergency contact number",
        },
        // ── Address details ───────────────────────────────────────────────────
        address: { type: "string", description: "Current address" },
        permanent_address: { type: "string", description: "Permanent address" },
        pincode: { type: "string", description: "Pincode" },
        native_place: { type: "string", description: "Native place" },
        // ── Experience details ────────────────────────────────────────────────
        total_work_experience_years: {
          type: "number",
          description: "Total work experience in years",
        },
        previous_company_name: {
          type: "string",
          description: "Previous company name",
        },
        previous_designation: {
          type: "string",
          description: "Previous designation",
        },
        last_salary: { type: "number", description: "Last drawn salary" },
        education_qualification: {
          type: "string",
          description: "Education qualification",
        },
        // ── Bank details ──────────────────────────────────────────────────────
        bank_name: { type: "string", description: "Bank name" },
        account_number: { type: "string", description: "Bank account number" },
        ifsc_code: { type: "string", description: "IFSC code" },
        account_holder_name: {
          type: "string",
          description: "Account holder name",
        },
        // ── Identity details ──────────────────────────────────────────────────
        aadhar_card: { type: "string", description: "Aadhaar card number" },
        pan_card_number: { type: "string", description: "PAN card number" },
        uan: { type: "string", description: "UAN (Universal Account Number)" },
        // ── Documents ─────────────────────────────────────────────────────────
        resume: {
          type: "string",
          format: "binary",
          description: "Resume file (PDF)",
        },
        offer_letter: {
          type: "string",
          format: "binary",
          description: "Offer letter document (PDF/image)",
        },
        appointment_letter: {
          type: "string",
          format: "binary",
          description: "Appointment letter document (PDF/image)",
        },
        id_proof: {
          type: "string",
          format: "binary",
          description: "ID proof document (PDF/image)",
        },
        address_proof: {
          type: "string",
          format: "binary",
          description: "Address proof document (PDF/image)",
        },
        education_certificates: {
          type: "string",
          format: "binary",
          description: "Education certificates (PDF/image)",
        },
        // ── Salary ────────────────────────────────────────────────────────────
        regime_type: {
          type: "string",
          enum: ["old", "new"],
          description: "Tax regime type",
        },
        salary_settings: {
          type: "string",
          description: "JSON array of salary settings",
        },
      },
    },
  })
  @UseInterceptors(
    FileFieldsInterceptor(employeeFileFields, employeeUploadsConfig),
  )
  update(
    @Param("id") id: string,
    @Body() updateEmployeeDto: UpdateEmployeeDto,
    @Req() request: Request,
    @UploadedFiles() files: Record<string, Express.Multer.File[]>,
  ) {
    return this.employeesService.update(
      +id,
      updateEmployeeDto,
      request.headers["authorization"],
      files,
    )
  }

  @Delete(":id")
  remove(@Param("id") id: string, @Req() request: Request) {
    return this.employeesService.remove(+id, request.headers["authorization"])
  }

  @Post("create-leave-balances/:id")
  createLeaveBalances(@Param("id") id: string, @Req() request: Request) {
    return this.employeesService.createLeaveBalancesForEmployee(
      +id,
      request.headers["authorization"],
    )
  }

  @Get("salary-history/:id")
  getSalaryHistory(@Param("id") id: string, @Req() request: Request) {
    return this.employeesService.getSalaryHistory(
      +id,
      request.headers["authorization"],
    )
  }

  @Put("salary-history/:id")
  updateSalaryHistory(
    @Param("id") id: string,
    @Body() updateSalaryHistoryDto: UpdateSalaryHistoryDto,
    @Req() request: Request,
  ) {
    return this.employeesService.updateSalaryHistory(
      +id,
      updateSalaryHistoryDto,
      request.headers["authorization"],
    )
  }

  @Patch("active-inactive/:id")
  activeInactiveEmployee(@Param("id") id: string, @Req() request: Request) {
    return this.employeesService.activeInactiveEmployee(
      +id,
      request.headers["authorization"],
    )
  }

  @Post("bulk-upload")
  @UseInterceptors(FileFieldsInterceptor([{ name: "file", maxCount: 1 }]))
  @ApiConsumes("multipart/form-data")
  @ApiBody({
    description: "Excel file for bulk employee upload",
    schema: {
      type: "object",
      properties: {
        file: {
          type: "string",
          format: "binary",
          description:
            "Excel file (.xlsx) containing employee data with NOTE row, headers, and data rows",
        },
      },
      required: ["file"],
    },
  })
  async bulkUploadEmployees(
    @UploadedFiles() files: Record<string, Express.Multer.File[]>,
    @Req() request: Request,
  ) {
    const file = files?.file?.[0]

    if (!file) {
      return {
        success: false,
        message: "Excel file is required",
        code: 400,
      }
    }

    if (!file.originalname.match(/\.(xlsx)$/)) {
      return {
        success: false,
        message: "Only Excel files (.xlsx) are allowed",
        code: 400,
      }
    }

    const result = await this.employeesService.bulkUploadEmployees(
      file.buffer,
      request.headers["authorization"],
    )

    // Always return JSON response, but include error file as base64 if there are errors
    if (
      result.success &&
      (result as any).data?.error_file &&
      (result as any).data.errors?.length > 0
    ) {
      const timestamp = new Date().toISOString().replace(/[:.]/g, "-")
      const filename = `employee-upload-errors-${timestamp}.xlsx`

      // Convert buffer to base64 for JSON response
      const errorFileBase64 = (result as any).data.error_file.toString("base64")

      return {
        ...result,
        data: {
          ...(result as any).data,
          error_file_name: filename,
          error_file_base64: errorFileBase64,
          // Remove the buffer from response to avoid circular reference
          error_file: undefined,
        },
      }
    }

    // Return normal JSON response if no errors
    return result
  }

  @Get("employee-projects/:id")
  async getEmployeeProjects(@Param("id") id: string) {
    return this.employeesService.getEmployeeProjects(+id)
  }

  @Post("assign-projects/:id")
  @ApiBody({
    description: "Assign multiple projects to an employee",
    type: AssignProjectsDto,
  })
  async assignProjects(
    @Param("id") id: string,
    @Body() assignProjectsDto: AssignProjectsDto,
    @Req() request: Request,
  ) {
    return this.employeesService.assignProjects(
      +id,
      assignProjectsDto.project_ids,
      request.headers["authorization"],
    )
  }
}
