<?php

namespace App\Http\Services;

use App\Models\Budget;
use App\Models\Payment;
use App\Models\Notification;
use App\Enums\ActionStatusType;
use App\Enums\NotificationType;
use App\Enums\UserType;
use App\Enums\ModuleType;
use App\Models\User;
use App\Utils\Helper;

class NotificationService
{
  public function createInfo($model, $targetRole, $departmentId = null, $actorName = "")
  {
    $targetUserIds = User::where('role', $targetRole);

    if ($departmentId) {
      $targetUserIds->whereHas('userDepartments', function ($q) use ($departmentId) {
        $q->where('departments.id', $departmentId);
      });
    }

    $targetUserIds = $targetUserIds->pluck('id')->toArray();

    if (empty($targetUserIds))
      return;

    $template = NotificationType::getContent(NotificationType::Info, $targetRole)['INFO_BUDGET_APPROVED'] ?? null;

    if (!$template)
      return;

    $message = $this->formatMessage($template, [
      '{name}' => $model->name,
      '{code}' => $model->code,
      '{manager_name}' => $actorName
    ]);

    $notifications = [];
    $timestamp = now();
    $link = $this->getUrl($model);

    foreach ($targetUserIds as $userId) {
      $notifications[] = [
        'user_id' => $userId,
        'department_id' => $departmentId,
        'module_type' => ModuleType::Budget,
        'type' => NotificationType::Info,
        'title' => $message['title'],
        'message' => $message['content'],
        'link' => $link,
        'is_read' => false,
        'created_at' => $timestamp,
        'updated_at' => $timestamp,
      ];
    }

    if (!empty($notifications)) {
      foreach (array_chunk($notifications, 100) as $chunk) {
        Notification::insert($chunk);
      }
    }
  }

  public function create($model, $action, $approvalLogId, $actor, $departmentId = null, $targetRole = null)
  {
    $data = $this->generateNotificationData($model, $action, $actor, $departmentId, $targetRole);

    if (empty($data))
      return;

    $notifications = [];
    $timestamp = now();
    $link = $this->getUrl($model);
    $targetUserIds = is_array($data['targetUserId']) ? $data['targetUserId'] : [$data['targetUserId']];
    $targetUserIds = array_unique(array_filter($targetUserIds));

    $budgetId = $model instanceof Budget ? $model->id : ($model->budget_id ?? null);
    $paymentId = $model instanceof Payment ? $model->id : null;
    $moduleType = $model instanceof Budget ? ModuleType::Budget : ($model instanceof Payment ? ModuleType::Payment : null);

    foreach ($targetUserIds as $userId) {
      $notifications[] = [
        'user_id' => $userId,
        'department_id' => $departmentId,
        'approval_log_id' => $approvalLogId,
        'budget_id' => $budgetId,
        'payment_id' => $paymentId,
        'module_type' => $moduleType,
        'type' => $data['type'],
        'title' => $data['message']['title'],
        'message' => $data['message']['content'],
        'link' => $link,
        'is_read' => false,
        'created_at' => $timestamp,
        'updated_at' => $timestamp,
      ];
    }

    if (!empty($notifications)) {
      foreach (array_chunk($notifications, 100) as $chunk) {
        Notification::insert($chunk);
      }
    }
  }

  private function generateNotificationData($model, $action, $actor, $departmentId, $targetRole)
  {
    if ($model instanceof Budget) {
      return $this->handleBudgetNotification($model, $action, $actor, $departmentId, $targetRole);
    } elseif ($model instanceof Payment) {
      return $this->handlePaymentNotification($model, $action, $actor);
    }
    return null;
  }

  private function handleBudgetNotification($budget, $action, $actor, $departmentId, $targetRole)
  {
    switch ($action) {
      case ActionStatusType::Submit:
        if (!$targetRole || !$departmentId)
          return null;

        // Batch Target: All users with targetRole in departmentId
        $targetUserIds = User::where('role', $targetRole)
          ->whereHas('userDepartments', function ($q) use ($departmentId) {
            $q->where('departments.id', $departmentId);
          })
          ->pluck('id')
          ->toArray();

        if (empty($targetUserIds))
          return null;

        return [
          'targetUserId' => $targetUserIds, // Array of IDs
          'type' => NotificationType::ApprovalRequest,
          'message' => $this->formatMessage(
            NotificationType::getContent(NotificationType::ApprovalRequest, 'manager')['SUBMISSION_RECEIVED'],
            ['{user_name}' => $actor->name, '{name}' => $budget->name, '{code}' => $budget->code, '{amount}' => Helper::formatCurrency($budget->debit_amount)]
          )
        ];

      case ActionStatusType::Approve:
        // Direct Target: To requester
        $messageTemplate = NotificationType::getContent(NotificationType::Info, 'user')['BUDGET_APPROVED'];

        return [
          'targetUserId' => $budget->user_id,
          'type' => NotificationType::Info,
          'message' => $this->formatMessage(
            $messageTemplate,
            ['{name}' => $budget->name, '{code}' => $budget->code]
          )
        ];

      case ActionStatusType::Reject:
        // Direct Target: To requester
        return [
          'targetUserId' => $budget->user_id,
          'type' => NotificationType::Info,
          'message' => $this->formatMessage(
            NotificationType::getContent(NotificationType::Info, 'user')['BUDGET_REJECTED'],
            ['{name}' => $budget->name, '{code}' => $budget->code]
          )
        ];

      case ActionStatusType::Revise:
        // Direct Target: To requester
        return [
          'targetUserId' => $budget->user_id,
          'type' => NotificationType::ApprovalRequest,
          'message' => $this->formatMessage(
            NotificationType::getContent(NotificationType::ApprovalRequest, 'user')['REVISION_REQUESTED'],
            ['{name}' => $budget->name, '{code}' => $budget->code]
          )
        ];
    }
    return null;
  }

  private function handlePaymentNotification($payment, $action, $actor)
  {
    $budget = $payment->budget;
    switch ($action) {
      case ActionStatusType::Reject:
        return [
          'targetUserId' => $payment->user_id ?? $budget->user_id,
          'type' => NotificationType::Info,
          'message' => "Payment for {$budget->code} rejected.",
        ];
      case ActionStatusType::Approve:
        return [
          'targetUserId' => $payment->user_id ?? $budget->user_id,
          'type' => NotificationType::Info,
          'message' => $this->formatMessage(
            NotificationType::getContent(NotificationType::Info, 'user')['BUDGET_PAID'],
            ['{name}' => $budget->name, '{code}' => $budget->code]
          )
        ];
    }
    return null;
  }

  private function formatMessage($template, $replacements)
  {
    return [
      'title' => $template['title'],
      'content' => str_replace(array_keys($replacements), array_values($replacements), $template['message'])
    ];
  }

  private function getUrl($model)
  {
    $q = urlencode(urlencode($model->code));
    if ($model instanceof Budget) {
      return "/admin/budgets?q={$q}&searchBy=code";
    }
    if ($model instanceof Payment) {
      return "/admin/payments?q={$q}&searchBy=code";
    }
    return "#";
  }
}
