<?php

namespace App\Processors\Customer;

use App\Entities\Customer\ServiceEntity;
use App\Entities\Equipment\ServerEntity;
use App\Entities\PaymentEntity;
use App\Services\Customer\ServiceService;
use App\Services\Equipment\ServerService;
use App\Services\MyLogService;
use App\Services\PaymentService;
use CodeIgniter\Database\BaseConnection;
use DateTimeImmutable;
use DateTimeZone;
use RuntimeException;

class ServiceV1Processor
{
  public function __construct(
    private BaseConnection $db,
    private ServiceService $serviceService,
    private ServerService  $serverService,
    private PaymentService $paymentService,
    private MyLogService $logService,
  ) {}

  /** 서버 연결 */
  public function setServer(ServiceEntity $entity, string $serverinfo_uid, array $formDatas = []): ServerEntity
  {
    $serverEntity = $this->serverService->getEntity($serverinfo_uid);
    if (!$serverEntity instanceof ServerEntity) {
      throw new RuntimeException("[{$serverinfo_uid}]에 대한 서버정보를 찾을 수 없습니다.");
    }
    $formDatas['clientinfo_uid']  = $entity->getClientInfoUID();
    $formDatas['serviceinfo_uid'] = $entity->getPK();
    $formDatas['status']          = STATUS['OCCUPIED'];
    return $this->serverService->getModel()->modify($serverEntity, $formDatas);
  }
  /** 서버 연결 해지 */
  public function unsetServer(string $serverinfo_uid): ServerEntity
  {
    $serverEntity = $this->serverService->getEntity($serverinfo_uid);
    if (!$serverEntity instanceof ServerEntity) {
      throw new RuntimeException("[{$serverinfo_uid}]에 대한 서버정보를 찾을 수 없습니다.");
    }
    return $this->serverService->getModel()->modify($serverEntity, [
      'clientinfo_uid'  => null,
      'serviceinfo_uid' => null,
      'format_at'       => date("Y-m-d"),
      'status'          => STATUS['AVAILABLE'],
    ]);
  }
  /** 결제 생성 */
  public function createPayment(ServiceEntity $entity, int $amount): PaymentEntity
  {
    $billingAt = new DateTimeImmutable($entity->getBillingAt(), new DateTimeZone('Asia/Tokyo'));
    return $this->paymentService->getModel()->create([
      'clientinfo_uid'  => $entity->getClientInfoUID(),
      'serviceinfo_uid' => $entity->getPK(),
      'serverinfo_uid'  => $entity->getServerInfoUID(), //서버정보 번호
      'title'           => sprintf('[%s] %s 서비스비용', $entity->getTitle(), $billingAt->format('Y년 n월')),
      'amount'          => $amount,
      'billing'         => PAYMENT['BILLING']['MONTH'],
      'billing_at'      => $billingAt->format('Y-m-d'),
    ]);
  }
  /** 결제 수정 */
  public function modifyPayment(ServiceEntity $entity, string $payment_uid, int $amount): PaymentEntity
  {
    $paymentEntity = $this->paymentService->getEntity($payment_uid);
    if (!$paymentEntity instanceof PaymentEntity) {
      throw new RuntimeException("[{$payment_uid}]에 대한 결제정보를 찾을 수 없습니다.");
    }

    $billingAt = new DateTimeImmutable($entity->getBillingAt(), new DateTimeZone('Asia/Tokyo'));

    return $this->paymentService->getModel()->modify($paymentEntity, [
      'clientinfo_uid'  => $entity->getClientInfoUID(),
      'serviceinfo_uid' => $entity->getPK(),
      'serverinfo_uid'  => $entity->getServerInfoUID(),
      'title'           => sprintf('[%s] %s 서비스비용', $entity->getTitle(), $billingAt->format('Y년 n월')),
      'amount'          => $amount,
      'billing'         => PAYMENT['BILLING']['MONTH'],
      'billing_at'      => $billingAt->format('Y-m-d'),
    ]);
  }

  /** 결제 삭제(서비스UID,서버UID만 NULL 처리하고 다른정보는 그냥 두고 수정한다.) */
  public function deletePayment(string $payment_uid): PaymentEntity
  {
    $paymentEntity = $this->paymentService->getEntity($payment_uid);
    if (!$paymentEntity instanceof PaymentEntity) {
      throw new RuntimeException("[{$payment_uid}]에 대한 결제정보를 찾을 수 없습니다.");
    }
    return $this->paymentService->getModel()->modify($paymentEntity, [
      'serviceinfo_uid' => null,
      'serverinfo_uid'  => null,
    ]);
  }
  /** 로그 생성*/
  public function addLog(string $title, string $status): void
  {
    $this->logService->getModel()->create(['title'  => $title, 'status' => $status,]);
  }

  /** 최종 결과만 필요할 때 */
  public function createService(array $formDatas): ServiceEntity
  {
    $this->db->transStart();
    if (!isset($formDatas['serverinfo_uid'])) {
      throw new RuntimeException('서버가 지정되지 않았습니다.');
    }
    // 1) 서비스 추가
    $entity = $this->serviceService->getModel()->create($formDatas);
    // 2) 서버 연결 
    $serverEntity = $this->setServer($entity, $entity->getServerInfoUID());
    // 3) 금액 계산
    $amount = $this->serviceService->getCalculatedAmount($entity, $serverEntity);
    // 4) 결제 생성
    $paymentEntity = $this->createPayment($entity,  $amount);
    // 5) 로그 (필요 시 이벤트로 대체)
    $this->addLog("{$entity->getCustomTitle()} 서비스 추가", $entity->getStatus());
    // 6) 서비스 갱신(FK 반영)
    $this->serviceService->getModel()->modify($entity, [
      'title' => $entity->getCustomTitle(),
      'serverinfo_id' => $serverEntity->getPK(),
      'payment_uid'   => $paymentEntity->getPK(),
    ]);
    $this->db->transComplete();
    if ($this->db->transStatus() === false) {
      throw new RuntimeException('트랜잭션 실패');
    }
    return $entity;
  }

  public function modifyService(ServiceEntity $entity, array $formDatas): ServiceEntity
  {
    $this->db->transStart();
    if (!isset($formDatas['serverinfo_uid'])) {
      throw new RuntimeException('변경할 서버가 지정되지 않았습니다.');
    }
    // 서버번호가 변경되었다면 기존 서버 연결 해지
    if ($entity->getServerInfoUID() !== null && $entity->getServerInfoUID() !== $formDatas['serverinfo_uid']) {
      $this->unsetServer($entity->getServerInfoUID());
    }
    // 1) 서비스정보 수정 
    $entity = $this->serviceService->getModel()->modify($entity, $formDatas);
    // 2) 서버 재연결
    $serverEntity = $this->setServer($entity, $entity->getServerInfoUID());
    // 3) 금액 계산
    $amount = $this->serviceService->getCalculatedAmount($entity, $serverEntity);
    // 4) 결제 정보 수정
    $paymentEntity = $this->modifyPayment($entity, $entity->getPaymentUID(), $amount);
    // 5) 로그
    $this->addLog("{$entity->getCustomTitle()} 서비스 수정", $entity->getStatus());
    // 6) FK 반영
    $this->serviceService->getModel()->modify($entity, [
      'title'         => $entity->getCustomTitle(),
      'serverinfo_id' => $serverEntity->getPK(),
      'payment_uid'   => $paymentEntity->getPK(),
    ]);
    $this->db->transComplete();
    if ($this->db->transStatus() === false) {
      throw new RuntimeException('트랜잭션 실패');
    }
    return $entity;
  }

  public function deleteService(ServiceEntity $entity): ServiceEntity
  {
    $this->db->transStart();
    // 1) 결제정보 분리
    if ($entity->getPaymentUID()) {
      $this->deletePayment($entity->getPaymentUID());
    }
    // 2) 연결된 모든 서버 해지 (★ 오타 수정: serviceinfo_uid)
    foreach ($this->serverService->getEntities(['serviceinfo_uid' => $entity->getPK()]) as $serverEntity) {
      $this->unsetServer($serverEntity->getPK()); // PK가 uid면 OK
    }
    // 3) 로그
    $this->addLog("[{$entity->getCustomTitle()}] 서비스 해지", $entity->getStatus());
    // 4) 서비스 삭제
    $this->serviceService->delete($entity);
    $this->db->transComplete();
    if ($this->db->transStatus() === false) {
      throw new RuntimeException('트랜잭션 실패');
    }
    return $entity;
  }
}
