import { Response, NextFunction } from 'express';
import { AuthRequest } from '../../shared/middleware/auth';
import { portalService } from './portal.service';
import { ResponseFormatter } from '../../shared/utils/responseFormatter';

export class PortalController {
  async getMe(req: AuthRequest, res: Response, next: NextFunction) {
    try {
      const data = await portalService.getMe(req.user?.employeeId);
      res.json(ResponseFormatter.success(data));
    } catch (error) {
      next(error);
    }
  }

  async getMyLoans(req: AuthRequest, res: Response, next: NextFunction) {
    try {
      const loans = await portalService.getMyLoans(req.user?.employeeId);
      res.json(ResponseFormatter.success(loans));
    } catch (error) {
      next(error);
    }
  }

  async submitLoanRequest(req: AuthRequest, res: Response, next: NextFunction) {
    try {
      const loan = await portalService.submitLoanRequest(req.user?.employeeId, req.body, req.user!.id);
      res.status(201).json(ResponseFormatter.success(loan, 'تم إرسال طلب القرض - Loan request submitted'));
    } catch (error) {
      next(error);
    }
  }

  async getMyLeaveBalance(req: AuthRequest, res: Response, next: NextFunction) {
    try {
      const year = req.query.year ? parseInt(req.query.year as string) : undefined;
      const balance = await portalService.getMyLeaveBalance(req.user?.employeeId, year);
      res.json(ResponseFormatter.success(balance));
    } catch (error) {
      next(error);
    }
  }

  async getMyLeaves(req: AuthRequest, res: Response, next: NextFunction) {
    try {
      const leaves = await portalService.getMyLeaves(req.user?.employeeId);
      res.json(ResponseFormatter.success(leaves));
    } catch (error) {
      next(error);
    }
  }
  async getManagedLeaves(req: AuthRequest, res: Response, next: NextFunction) {
    try {
      const status = req.query.status as string | undefined;
      const leaves = await portalService.getManagedLeaves(req.user?.employeeId, status);
      res.json(ResponseFormatter.success(leaves));
    } catch (error) {
      next(error);
    }
  }

  async approveManagedLeave(req: AuthRequest, res: Response, next: NextFunction) {
    try {
      const leave = await portalService.approveManagedLeave(req.user?.employeeId, req.params.id, req.user!.id);
      res.json(ResponseFormatter.success(leave, 'تمت الموافقة على الإجازة من قبل مدير القسم - Leave approved by department manager'));
    } catch (error) {
      next(error);
    }
  }

  async rejectManagedLeave(req: AuthRequest, res: Response, next: NextFunction) {
    try {
      const { rejectedReason } = req.body;
      const leave = await portalService.rejectManagedLeave(
        req.user?.employeeId,
        req.params.id,
        rejectedReason || '',
        req.user!.id
      );
      res.json(ResponseFormatter.success(leave, 'تم رفض طلب الإجازة من قبل مدير القسم - Leave rejected by department manager'));
    } catch (error) {
      next(error);
    }
  }


  async getMyOvertimeRequests(req: AuthRequest, res: Response, next: NextFunction) {
    try {
      const data = await portalService.getMyOvertimeRequests(req.user?.employeeId);
      res.json(ResponseFormatter.success(data));
    } catch (error) {
      next(error);
    }
  }

  async submitOvertimeRequest(req: AuthRequest, res: Response, next: NextFunction) {
    try {
      const data = {
        date: req.body.date,
        hours: req.body.hours,
        reason: req.body.reason,
      };

      const result = await portalService.submitOvertimeRequest(req.user?.employeeId, data, req.user!.id);
      res.status(201).json(ResponseFormatter.success(result, 'تم إرسال طلب الساعات الإضافية'));
    } catch (error) {
      next(error);
    }
  }

  async getManagedOvertimeRequests(req: AuthRequest, res: Response, next: NextFunction) {
    try {
      const data = await portalService.getManagedOvertimeRequests(req.user?.employeeId);
      res.json(ResponseFormatter.success(data));
    } catch (error) {
      next(error);
    }
  }

  async approveManagedOvertimeRequest(req: AuthRequest, res: Response, next: NextFunction) {
    try {
      const result = await portalService.approveManagedOvertimeRequest(
        req.user?.employeeId,
        req.params.attendanceId,
        req.user!.id
      );
      res.json(ResponseFormatter.success(result, 'تمت الموافقة على طلب الساعات الإضافية'));
    } catch (error) {
      next(error);
    }
  }

  async rejectManagedOvertimeRequest(req: AuthRequest, res: Response, next: NextFunction) {
    try {
      const result = await portalService.rejectManagedOvertimeRequest(
        req.user?.employeeId,
        req.params.attendanceId,
        req.body.rejectedReason || '',
        req.user!.id
      );
      res.json(ResponseFormatter.success(result, 'تم رفض طلب الساعات الإضافية'));
    } catch (error) {
      next(error);
    }
  }

    async submitLeaveRequest(req: AuthRequest, res: Response, next: NextFunction) {
  try {
    const body = { ...req.body };
    const leaveType = String(body.leaveType || '').toUpperCase();

    let startDate: Date;
    let endDate: Date;

    if (leaveType === 'HOURLY' && body.leaveDate && body.startTime && body.endTime) {
      startDate = new Date(`${body.leaveDate}T${body.startTime}:00+03:00`);
      endDate = new Date(`${body.leaveDate}T${body.endTime}:00+03:00`);
    } else {
      startDate = new Date(body.startDate);
      endDate = new Date(body.endDate);
    }

    if (Number.isNaN(startDate.getTime()) || Number.isNaN(endDate.getTime())) {
      return res.status(400).json({
        success: false,
        message: 'تاريخ أو وقت الإجازة غير صالح - Invalid leave date or time',
      });
    }

    const isInvalidRange = leaveType === 'HOURLY'
      ? endDate <= startDate
      : endDate < startDate;

    if (isInvalidRange) {
      return res.status(400).json({
        success: false,
        message: 'وقت/تاريخ النهاية يجب أن يكون بعد البداية - End date/time must be after start date/time',
      });
    }

    const data = {
      leaveType,
      startDate,
      endDate,
      reason: body.reason || undefined,
    };

    const leave = await portalService.submitLeaveRequest(
      req.user?.employeeId,
      data,
      req.user!.id
    );

    res
      .status(201)
      .json(
        ResponseFormatter.success(
          leave,
          'تم إرسال طلب الإجازة - Leave request submitted'
        )
      );
  } catch (error) {
    next(error);
  }
}

  async getMyPurchaseRequests(req: AuthRequest, res: Response, next: NextFunction) {
    try {
      const requests = await portalService.getMyPurchaseRequests(req.user?.employeeId);
      res.json(ResponseFormatter.success(requests));
    } catch (error) {
      next(error);
    }
  }

  async submitPurchaseRequest(req: AuthRequest, res: Response, next: NextFunction) {
    try {
      const pr = await portalService.submitPurchaseRequest(req.user?.employeeId, req.body, req.user!.id);
      res.status(201).json(ResponseFormatter.success(pr, 'تم إرسال طلب الشراء - Purchase request submitted'));
    } catch (error) {
      next(error);
    }
  }

    async getMyExpenseClaims(req: AuthRequest, res: Response, next: NextFunction) {
    try {
      const data = await portalService.getMyExpenseClaims(req.user?.employeeId);
      res.json(ResponseFormatter.success(data));
    } catch (error) {
      next(error);
    }
  }

  async submitExpenseClaim(req: AuthRequest, res: Response, next: NextFunction) {
    try {
      const body = { ...req.body };

      if (typeof body.items === 'string') {
        body.items = JSON.parse(body.items);
      }

      const files = (req.files as Express.Multer.File[] | undefined) || [];

      const data = await portalService.submitExpenseClaim(
        req.user?.employeeId,
        body,
        req.user!.id,
        files
      );

      res
        .status(201)
        .json(
          ResponseFormatter.success(
            data,
            'تم إرسال كشف المصاريف - Expense claim submitted'
          )
        );
    } catch (error: any) {
      if (error.message?.includes('نوع الملف غير مدعوم')) {
        return res.status(400).json({
          success: false,
          message: error.message,
        });
      }

      next(error);
    }
  }
  async viewExpenseClaimAttachment(
  req: AuthRequest,
  res: Response,
  next: NextFunction
) {
  try {
    const attachment = await portalService.getExpenseClaimAttachmentFile(
      req.params.attachmentId
    );

    const encodedFileName = encodeURIComponent(attachment.originalName);

    res.setHeader('Content-Type', attachment.mimeType);
    res.setHeader(
      'Content-Disposition',
      `inline; filename*=UTF-8''${encodedFileName}`
    );

    res.sendFile(attachment.path);
  } catch (error) {
    next(error);
  }
}

  async getManagedExpenseClaims(req: AuthRequest, res: Response, next: NextFunction) {
    try {
      const status = req.query.status as string | undefined;
      const search = req.query.search as string | undefined;
      const paid = req.query.paid as string | undefined;
      const data = await portalService.getManagedExpenseClaims(
        req.user?.employeeId,
        status,
        search,
        paid,
      );
      res.json(ResponseFormatter.success(data));
    } catch (error) {
      next(error);
    }
  }

  async approveManagedExpenseClaim(req: AuthRequest, res: Response, next: NextFunction) {
  try {
    const { approvalNote } = req.body;

    const data = await portalService.approveManagedExpenseClaim(
      req.user?.employeeId,
      req.params.id,
      req.user!.id,
      approvalNote
    );

    res.json(ResponseFormatter.success(data, 'تمت الموافقة على كشف المصاريف - Expense claim approved'));
  } catch (error) {
    next(error);
  }
}

  async rejectManagedExpenseClaim(req: AuthRequest, res: Response, next: NextFunction) {
    try {
      const { rejectedReason } = req.body;
      const data = await portalService.rejectManagedExpenseClaim(
        req.user?.employeeId,
        req.params.id,
        rejectedReason || '',
        req.user!.id
      );
      res.json(ResponseFormatter.success(data, 'تم رفض كشف المصاريف - Expense claim rejected'));
    } catch (error) {
      next(error);
    }
  }

  async markExpenseClaimPaid(req: AuthRequest, res: Response, next: NextFunction) {
    try {
      const isPaid = Boolean(req.body?.isPaid);
      const data = await portalService.markExpenseClaimPaid(
        req.user?.employeeId,
        req.params.id,
        isPaid,
        req.user!.id
      );
      res.json(
        ResponseFormatter.success(
          data,
          isPaid
            ? 'تم تعليم كشف المصاريف كمقبوض - Expense claim marked as paid'
            : 'تم إلغاء تعليم القبض - Paid mark removed'
        )
      );
    } catch (error) {
      next(error);
    }
  }

  async getMyAttendance(req: AuthRequest, res: Response, next: NextFunction) {
    try {
      const month = req.query.month ? parseInt(req.query.month as string) : undefined;
      const year = req.query.year ? parseInt(req.query.year as string) : undefined;
      const attendance = await portalService.getMyAttendance(req.user?.employeeId, month, year);
      res.json(ResponseFormatter.success(attendance));
    } catch (error) {
      next(error);
    }
  }

  async getMySalaries(req: AuthRequest, res: Response, next: NextFunction) {
    try {
      const salaries = await portalService.getMySalaries(req.user?.employeeId);
      res.json(ResponseFormatter.success(salaries));
    } catch (error) {
      next(error);
    }
  }

  // ========== PERSONAL EDIT/DELETE (pending only) ==========

  async updateMyLeave(req: AuthRequest, res: Response, next: NextFunction) {
    try {
      const body = { ...req.body };
      const leaveType = body.leaveType ? String(body.leaveType).toUpperCase() : undefined;

      let startDate: Date | undefined;
      let endDate: Date | undefined;

      if (leaveType === 'HOURLY' && body.leaveDate && body.startTime && body.endTime) {
        startDate = new Date(`${body.leaveDate}T${body.startTime}:00+03:00`);
        endDate = new Date(`${body.leaveDate}T${body.endTime}:00+03:00`);
      } else if (body.startDate || body.endDate) {
        startDate = body.startDate ? new Date(body.startDate) : undefined;
        endDate = body.endDate ? new Date(body.endDate) : undefined;
      }

      const result = await portalService.updateMyLeave(
        req.user?.employeeId,
        req.params.id,
        {
          leaveType,
          startDate,
          endDate,
          reason: body.reason,
        },
        req.user!.id
      );
      res.json(ResponseFormatter.success(result, 'تم تعديل طلب الإجازة'));
    } catch (error) {
      next(error);
    }
  }

  async deleteMyLeave(req: AuthRequest, res: Response, next: NextFunction) {
    try {
      const result = await portalService.deleteMyLeave(
        req.user?.employeeId,
        req.params.id,
        req.user!.id
      );
      res.json(ResponseFormatter.success(result, 'تم حذف طلب الإجازة'));
    } catch (error) {
      next(error);
    }
  }

  async updateMyPurchaseRequest(req: AuthRequest, res: Response, next: NextFunction) {
    try {
      const result = await portalService.updateMyPurchaseRequest(
        req.user?.employeeId,
        req.params.id,
        req.body,
        req.user!.id
      );
      res.json(ResponseFormatter.success(result, 'تم تعديل طلب الشراء'));
    } catch (error) {
      next(error);
    }
  }

  async deleteMyPurchaseRequest(req: AuthRequest, res: Response, next: NextFunction) {
    try {
      const result = await portalService.deleteMyPurchaseRequest(
        req.user?.employeeId,
        req.params.id,
        req.user!.id
      );
      res.json(ResponseFormatter.success(result, 'تم حذف طلب الشراء'));
    } catch (error) {
      next(error);
    }
  }

  async updateMyLoan(req: AuthRequest, res: Response, next: NextFunction) {
    try {
      const result = await portalService.updateMyLoan(
        req.user?.employeeId,
        req.params.id,
        req.body,
        req.user!.id
      );
      res.json(ResponseFormatter.success(result, 'تم تعديل طلب القرض'));
    } catch (error) {
      next(error);
    }
  }

  async deleteMyLoan(req: AuthRequest, res: Response, next: NextFunction) {
    try {
      const result = await portalService.deleteMyLoan(
        req.user?.employeeId,
        req.params.id,
        req.user!.id
      );
      res.json(ResponseFormatter.success(result, 'تم حذف طلب القرض'));
    } catch (error) {
      next(error);
    }
  }

  async updateMyOvertimeRequest(req: AuthRequest, res: Response, next: NextFunction) {
    try {
      const result = await portalService.updateMyOvertimeRequest(
        req.user?.employeeId,
        req.params.attendanceId,
        { hours: req.body.hours, reason: req.body.reason },
        req.user!.id
      );
      res.json(ResponseFormatter.success(result, 'تم تعديل طلب الساعات الإضافية'));
    } catch (error) {
      next(error);
    }
  }

  async deleteMyOvertimeRequest(req: AuthRequest, res: Response, next: NextFunction) {
    try {
      const result = await portalService.deleteMyOvertimeRequest(
        req.user?.employeeId,
        req.params.attendanceId,
        req.user!.id
      );
      res.json(ResponseFormatter.success(result, 'تم حذف طلب الساعات الإضافية'));
    } catch (error) {
      next(error);
    }
  }

  async updateMyExpenseClaim(req: AuthRequest, res: Response, next: NextFunction) {
    try {
      const body = { ...req.body };
      if (typeof body.items === 'string') {
        body.items = JSON.parse(body.items);
      }
      if (typeof body.removeAttachmentIds === 'string') {
        try {
          body.removeAttachmentIds = JSON.parse(body.removeAttachmentIds);
        } catch {
          body.removeAttachmentIds = [];
        }
      }
      const files = (req.files as Express.Multer.File[] | undefined) || [];
      const data = await portalService.updateMyExpenseClaim(
        req.user?.employeeId,
        req.params.id,
        body,
        req.user!.id,
        files
      );
      res.json(ResponseFormatter.success(data, 'تم تعديل كشف المصاريف'));
    } catch (error: any) {
      if (error.message?.includes('نوع الملف غير مدعوم')) {
        return res.status(400).json({ success: false, message: error.message });
      }
      next(error);
    }
  }

  async deleteMyExpenseClaim(req: AuthRequest, res: Response, next: NextFunction) {
    try {
      const result = await portalService.deleteMyExpenseClaim(
        req.user?.employeeId,
        req.params.id,
        req.user!.id
      );
      res.json(ResponseFormatter.success(result, 'تم حذف كشف المصاريف'));
    } catch (error) {
      next(error);
    }
  }
}

export const portalController = new PortalController();
