<?php

namespace App\Services;

use App\Config\DatasourceConfig;
use App\Models\ActivityLogType;
use App\Repositories\StatusTicketRepo;
use App\Repositories\TeknisiRepo;
use App\Repositories\TicketAssignmentRepo;
use App\Repositories\TicketRepo;

class TicketAssignmentService
{

  private TicketAssignmentRepo $ticketAssignmentRepo;
  private TicketRepo $ticketRepo;
  private StatusTicketRepo $statusTicketRepo;
  private ActivityLogService $activityLogService;
  private TeknisiRepo $teknisiRepo;

  public function __construct()
  {
    $this->ticketAssignmentRepo = new TicketAssignmentRepo();
    $this->ticketRepo = new TicketRepo();
    $this->statusTicketRepo = new StatusTicketRepo();
    $this->activityLogService = new ActivityLogService();
    $this->teknisiRepo = new TeknisiRepo();
  }


  public function save(int $ticketId, int $teknisiId, string $statusName, string $userId, ?string $catatan = null): void
  {

    $status = $this->statusTicketRepo->findByNamaStatus($statusName)[0];

    if (!$status) {
      throw new \Exception('Status tidak valid.');
    }

    $statusId = $status->getId();

    // validasi jika status ASSIGN dan sudah ada assignment
    $invalid = $this->ticketAssignmentRepo->existsActiveAssignment($ticketId) && $statusName === 'ASSIGNED';
    if ($invalid) {
      throw new \Exception(
        'Tiket ini sudah ditugaskan kepada teknisi.'
      );
    }

    $connection = (new DatasourceConfig())->connect();
    $connection->beginTransaction();

    $this->ticketAssignmentRepo->save($connection, $ticketId, $teknisiId, $statusId, $catatan);
    $this->ticketRepo->updateStatus($ticketId, $statusId, $connection);

    $teknisi = $this->teknisiRepo->findById($teknisiId);

    $this->activityLogService->create(
      connection: $connection,
      targetUserId: $teknisi->getUserId(),
      ticketId: $ticketId,
      userId: $userId,
      status: $statusName,
      log: ActivityLogType::ASSIGN,
    );

    $connection->commit();
  }

  public function update(int $ticketId, int $teknisiId, string $statusPenugasan, string $catatan, ?bool $solved = false)
  {
    $this->ticketAssignmentRepo->update($teknisiId, $statusPenugasan, $catatan, $ticketId, $solved);
  }

  // find by ticket id
  public function findByTicketId(int $ticketId)
  {
    return $this->ticketAssignmentRepo->findByTicketId($ticketId);
  }

  public function escalate(int $ticketId, int $teknisiUserId, string $catatan, int $userId)
  {
    $connection = (new DatasourceConfig())->connect();
    $connection->beginTransaction();

    // update status tiket menjadi escalated
    $status = $this->statusTicketRepo->findByNamaStatus("ESCALATED")[0];
    $this->ticketRepo->updateStatus($ticketId, $status->getId(), $connection);

    // update assignment
    $teknisiId = $this->teknisiRepo->findByUserId($teknisiUserId)->getId();
    $this->update($ticketId, $teknisiId, "DITUGASKAN", $catatan);

    // update log
    $this->activityLogService->create(
      connection: $connection,
      userId: $userId,
      ticketId: $ticketId,
      targetUserId: $teknisiUserId,
      status: $status->getNamaStatus(),
      log: ActivityLogType::ESCALATE
    );

    $connection->commit();
  }

  public function findByTeknisiId(int $teknisiId)
  {
    return $this->ticketAssignmentRepo->findByTeknisiId($teknisiId);
  }
}
