import { Router } from 'express';
import { hrController } from './hr.controller';
import { portalController } from './portal.controller';
import { authenticate, authorize } from '../../shared/middleware/auth';
import multer from 'multer';
import path from 'path';
import fs from 'fs';
import crypto from 'crypto';
import { config } from '../../config';

const router = Router();
const expenseClaimsUploadDir = path.join(config.upload.path, 'expense-claims');

if (!fs.existsSync(expenseClaimsUploadDir)) {
  fs.mkdirSync(expenseClaimsUploadDir, { recursive: true });
}

const expenseClaimStorage = multer.diskStorage({
  destination: (_req, _file, cb) => cb(null, expenseClaimsUploadDir),
  filename: (_req, file, cb) => {
    // Browsers send filenames in multipart/form-data as raw UTF-8 bytes,
    // but multer/busboy decode them as latin1 by default. For Arabic
    // (or any non-ASCII) filenames this produces mojibake like "ÙÙŠÙØ§...".
    // Reverse the misinterpretation: take the latin1 string back to bytes,
    // then decode as UTF-8. The service reads `decodedOriginalName` when
    // it persists the attachment to the DB.
    try {
      (file as any).decodedOriginalName = Buffer.from(
        file.originalname,
        'latin1'
      ).toString('utf8');
    } catch {
      (file as any).decodedOriginalName = file.originalname;
    }

    const safeName = (file.originalname || 'file').replace(/[^a-zA-Z0-9.-]/g, '_');
    cb(null, `${crypto.randomUUID()}-${safeName}`);
  },
});

const expenseClaimUpload = multer({
  storage: expenseClaimStorage,
  limits: { fileSize: config.upload.maxFileSize },

  fileFilter: (_req, file, cb) => {
    const allowedTypes = [
      'image/jpeg',
      'image/png',
      'image/webp',
      'image/gif',
      'application/pdf',
    ];

    if (!allowedTypes.includes(file.mimetype)) {
      return cb(
        new Error('نوع الملف غير مدعوم. يرجى رفع صورة أو ملف PDF.')
      );
    }

    cb(null, true);
  },
});

router.use(authenticate);

// ========== EMPLOYEE PORTAL (authenticate only, scoped by employeeId) ==========

router.get('/portal/me', portalController.getMe);
router.get('/portal/loans', portalController.getMyLoans);
router.post('/portal/loans', portalController.submitLoanRequest);
router.put('/portal/loans/:id', portalController.updateMyLoan);
router.delete('/portal/loans/:id', portalController.deleteMyLoan);
router.get('/portal/leave-balance', portalController.getMyLeaveBalance);
router.get('/portal/leaves', portalController.getMyLeaves);
router.post('/portal/leaves', portalController.submitLeaveRequest);
router.put('/portal/leaves/:id', portalController.updateMyLeave);
router.delete('/portal/leaves/:id', portalController.deleteMyLeave);

router.get(
  '/portal/managed-leaves',
  authorize('department_leave_requests', '*', 'read'),
  portalController.getManagedLeaves
);

router.post(
  '/portal/managed-leaves/:id/approve',
  authorize('department_leave_requests', '*', 'approve'),
  portalController.approveManagedLeave
);

router.post(
  '/portal/managed-leaves/:id/reject',
  authorize('department_leave_requests', '*', 'approve'),
  portalController.rejectManagedLeave
);

router.get('/portal/overtime-requests', portalController.getMyOvertimeRequests);
router.post('/portal/overtime-requests', portalController.submitOvertimeRequest);
router.put('/portal/overtime-requests/:attendanceId', portalController.updateMyOvertimeRequest);
router.delete('/portal/overtime-requests/:attendanceId', portalController.deleteMyOvertimeRequest);

router.get(
  '/portal/managed-overtime-requests',
  authorize('department_overtime_requests', '*', 'view'),
  portalController.getManagedOvertimeRequests
);

router.post(
  '/portal/managed-overtime-requests/:attendanceId/approve',
  authorize('department_overtime_requests', '*', 'approve'),
  portalController.approveManagedOvertimeRequest
);

router.post(
  '/portal/managed-overtime-requests/:attendanceId/reject',
  authorize('department_overtime_requests', '*', 'approve'),
  portalController.rejectManagedOvertimeRequest
);

router.get('/portal/purchase-requests', portalController.getMyPurchaseRequests);
router.post('/portal/purchase-requests', portalController.submitPurchaseRequest);
router.put('/portal/purchase-requests/:id', portalController.updateMyPurchaseRequest);
router.delete('/portal/purchase-requests/:id', portalController.deleteMyPurchaseRequest);
router.get('/portal/attendance', portalController.getMyAttendance);
router.get('/portal/salaries', portalController.getMySalaries);

router.get('/portal/expense-claims', portalController.getMyExpenseClaims);
router.post(
  '/portal/expense-claims',
  (req, res, next) => {
    // Accept up to 10 files under the form field "attachments".
    expenseClaimUpload.array('attachments', 10)(req, res, (error: any) => {
      if (error) {
        return res.status(400).json({
          success: false,
          message: error.message || 'تعذر رفع المرفقات',
        });
      }

      next();
    });
  },
  portalController.submitExpenseClaim
);
router.put(
  '/portal/expense-claims/:id',
  (req, res, next) => {
    expenseClaimUpload.array('attachments', 10)(req, res, (error: any) => {
      if (error) {
        return res.status(400).json({
          success: false,
          message: error.message || 'تعذر رفع المرفقات',
        });
      }
      next();
    });
  },
  portalController.updateMyExpenseClaim
);
router.delete('/portal/expense-claims/:id', portalController.deleteMyExpenseClaim);
router.get(
  '/portal/expense-claims/attachments/:attachmentId/view',
  portalController.viewExpenseClaimAttachment
);
router.get('/portal/managed-expense-claims', authorize('department_expense_claims', '*', 'read'), portalController.getManagedExpenseClaims);

router.post(
  '/portal/managed-expense-claims/:id/approve',
  authorize('department_expense_claims', '*', 'approve'),
  portalController.approveManagedExpenseClaim
);

router.post(
  '/portal/managed-expense-claims/:id/reject',
  authorize('department_expense_claims', '*', 'approve'),
  portalController.rejectManagedExpenseClaim
);

router.patch(
  '/portal/managed-expense-claims/:id/paid',
  authorize('department_expense_claims', '*', 'mark-as-paid'),
  portalController.markExpenseClaimPaid
);

// ========== EMPLOYEES ==========

router.get('/employees', authorize('hr', 'employees', 'read'), hrController.findAllEmployees);
router.get('/employees/:id', authorize('hr', 'employees', 'read'), hrController.findEmployeeById);
router.post('/employees', authorize('hr', 'employees', 'create'), hrController.createEmployee);
router.put('/employees/:id', authorize('hr', 'employees', 'update'), hrController.updateEmployee);
router.post('/employees/:id/terminate', authorize('hr', 'employees', 'terminate'), hrController.terminateEmployee);

// ========== ATTENDANCE ==========

router.post('/attendance', authorize('hr', 'attendance', 'create'), hrController.recordAttendance);
router.get('/attendance/:employeeId', authorize('hr', 'attendance', 'read'), hrController.getAttendance);
router.post('/attendance/sync', authorize('hr', 'attendance', 'create'), hrController.bulkSyncAttendance);

// ========== LEAVES ==========

router.get('/leaves', authorize('hr', 'leaves', 'read'), hrController.findAllLeaves);
router.post('/leaves', authorize('hr', 'leaves', 'create'), hrController.createLeaveRequest);
router.post('/leaves/:id/approve', authorize('hr', 'leaves', 'approve'), hrController.approveLeave);
router.post('/leaves/:id/reject', authorize('hr', 'leaves', 'approve'), hrController.rejectLeave);

// ========== SALARIES ==========

router.post('/salaries/process', authorize('hr', 'salaries', 'process'), hrController.processSalary);

// ========== DEPARTMENTS ==========

router.get('/departments', authorize('hr', 'all', 'read'), hrController.findAllDepartments);
router.get('/departments/hierarchy', authorize('hr', 'all', 'read'), hrController.getDepartmentsHierarchy);
router.post('/departments', authorize('hr', 'all', 'create'), hrController.createDepartment);
router.put('/departments/:id', authorize('hr', 'all', 'update'), hrController.updateDepartment);
router.delete('/departments/:id', authorize('hr', 'all', 'delete'), hrController.deleteDepartment);

// ========== POSITIONS ==========

router.get('/positions', authorize('hr', 'all', 'read'), hrController.findAllPositions);

// ========== LOANS ==========

router.get('/loans', authorize('hr', 'all', 'read'), hrController.findAllLoans);
router.get('/loans/:id', authorize('hr', 'all', 'read'), hrController.findLoanById);
router.post('/loans', authorize('hr', 'all', 'create'), hrController.createLoan);
router.post('/loans/:id/approve', authorize('hr', 'all', 'approve'), hrController.approveLoan);
router.post('/loans/:id/reject', authorize('hr', 'all', 'approve'), hrController.rejectLoan);
router.post('/loans/:id/pay-installment', authorize('hr', 'all', 'update'), hrController.recordLoanInstallmentPayment);

// ========== PURCHASE REQUESTS ==========

router.get('/purchase-requests', authorize('hr', 'all', 'read'), hrController.findAllPurchaseRequests);
router.get('/purchase-requests/:id', authorize('hr', 'all', 'read'), hrController.findPurchaseRequestById);
router.post('/purchase-requests', authorize('hr', 'all', 'create'), hrController.createPurchaseRequest);
router.post('/purchase-requests/:id/approve', authorize('hr', 'all', 'approve'), hrController.approvePurchaseRequest);
router.post('/purchase-requests/:id/reject', authorize('hr', 'all', 'approve'), hrController.rejectPurchaseRequest);

// ========== LEAVE ENTITLEMENTS ==========

router.get('/leave-balance/:employeeId', authorize('hr', 'all', 'read'), hrController.getLeaveBalance);
router.get('/leave-entitlements', authorize('hr', 'all', 'read'), hrController.findAllLeaveEntitlements);
router.post('/leave-entitlements', authorize('hr', 'all', 'create'), hrController.upsertLeaveEntitlement);

// ========== EMPLOYEE CONTRACTS ==========

router.get('/contracts', authorize('hr', 'all', 'read'), hrController.findAllEmployeeContracts);
router.get('/contracts/:id', authorize('hr', 'all', 'read'), hrController.findEmployeeContractById);
router.post('/contracts', authorize('hr', 'all', 'create'), hrController.createEmployeeContract);
router.put('/contracts/:id', authorize('hr', 'all', 'update'), hrController.updateEmployeeContract);

export default router;