<?php

namespace lib\Services;

use lib\Entities\ClientEntity;
use lib\Entities\ServiceEntity as Entity;
use lib\Entities\ServiceEntity;
use lib\Models\AddDbModel;
use lib\Models\ClientModel;
use lib\Models\ServiceModel as Model;

class ServiceService extends CommonService
{
  public function __construct()
  {
    parent::__construct();
  }
  final public function getClassName(): string
  {
    return "Service";
  }
  final public function getClassPath(): string
  {
    return $this->getClassName();
  }
  public function getModelClass(): string
  {
    return Model::class;
  }
  public function getEntityClass(): string
  {
    return Entity::class;
  }
  public function getEntityByCode(string $key): Entity|null|false
  {
    $this->getModel()->where('service_code', $key);
    return $this->getEntity();
  }

  //사용자별 서비스리스트트
  public function getEntitiesForCoupon(int $curPage, int $perPage, ?string $client_code = null): array
  {
    if ($client_code !== null) {
      $this->getModel()->where("client_code", $client_code);
    }
    $this->getModel()->whereNotIn("service_line", ['vpn', 'test', 'solo', 'substitution', 'event']);
    //Query문 Rest여부 -> 같은조건에 Count 받고, 결과값을 받고 싶을때는 continue()
    $this->getModel()->setContinue(true);
    $total = $this->getCount();
    //limit, offset 설정
    $this->getModel()->limit($perPage);
    $this->getModel()->offset(($curPage - 1) * $perPage);
    return [$total, $this->getEntities()];
  }

  //미지급금 리스트
  public function getEntitiesForNonPayment(int $curPage, int $perPage, string $mode, array $exclude_clients): array
  {
    switch ($mode) {
      case 'today':
        $this->getModel()->where("service_payment_date = CURDATE()");
        break;
      case '1day':
        $nonpaymentDay = 1;
        $this->getModel()->where("service_payment_date = Date_Add(CURDATE(),INTERVAL {$nonpaymentDay} DAY)");
        break;
      case '2day':
        $nonpaymentDay = 2;
        $this->getModel()->where("service_payment_date = Date_Add(CURDATE(),INTERVAL {$nonpaymentDay} DAY)");
        break;
      case '3day':
        $nonpaymentDay = 3;
        $this->getModel()->where("service_payment_date = Date_Add(CURDATE(),INTERVAL {$nonpaymentDay} DAY)");
        break;
    }
    $table = $this->getModel()->getTable();
    $clientTable = ClientModel::TABLE;
    $addDbTable = AddDbModel::TABLE;
    $this->getModel()->select("{$clientTable}.Client_Name,{$table}.service_code,service_line,server_code,service_ip,service_payment_date,service_amount,service_nonpayment,service_note,addDB_case,addDB_nonpayment,addDB_payment,addDB_accountStatus,addDB_ip,addDB_payment_date");
    $this->getModel()->join($clientTable, "{$table}.client_code = {$clientTable}.Client_Code");
    $this->getModel()->join($addDbTable, "{$table}.service_code = {$addDbTable}.service_code");
    $this->getModel()->whereNotIn("{$addDbTable}.client_code", $exclude_clients);
    $this->getModel()->whereNotIn("{$addDbTable}.addDB_accountStatus", ["complete"]);
    $this->getModel()->orderBy("service_payment_date", "DESC");
    //Query문 Rest여부 -> 같은조건에 Count 받고, 결과값을 받고 싶을때는 continue()
    $this->getModel()->setContinue(true);
    $total = $this->getCount();
    //limit, offset 설정
    $this->getModel()->limit($perPage);
    $this->getModel()->offset(($curPage - 1) * $perPage);
    return [$total, $this->getEntities()];
  }

  //미지급금 리스트
  public function getEntitiesForIpSearch(int $curPage, int $perPage, ?string $ip = null, $isIPV4 = true): array
  {
    if ($ip && $isIPV4) {
      $this->getModel()->where('service_ip', $ip);
    } elseif ($ip) {
      $this->getModel()->like('service_ip', $ip);
    }
    //Query문 Rest여부 -> 같은조건에 Count 받고, 결과값을 받고 싶을때는 continue()
    $this->getModel()->setContinue(true);
    $total = $this->getCount();
    //limit, offset 설정
    $this->getModel()->limit($perPage);
    $this->getModel()->offset(($curPage - 1) * $perPage);
    return [$total, $this->getEntities()];
  }

  //부가서비스스
  public function getEntitiesForExtra(int $curPage, int $perPage, array $service_codes): array
  {
    $this->getModel()->whereIn('service_code', $service_codes);
    //Query문 Rest여부 -> 같은조건에 Count 받고, 결과값을 받고 싶을때는 continue()
    $this->getModel()->setContinue(true);
    $total = $this->getCount();
    //limit, offset 설정
    $this->getModel()->limit($perPage);
    $this->getModel()->offset(($curPage - 1) * $perPage);
    return [$total, $this->getEntities()];
  }

  //최근 $day일간 신규서비스 카운트
  public function getLatestCount(int $day, array $excepts): int|string
  {
    $this->getModel()->where("service_open_date > DATE_ADD(now(), INTERVAL -{$day} DAY)");
    $this->getModel()->where("service_status", 'o');
    $this->getModel()->whereNotIn("service_line", $excepts);
    $count =  $this->getModel()->count();
    // echo __FUNCTION__ . ":" . $this->getModel()->getLastQuery();
    return $count;
  }
  //미지급서비스 카운트
  public function getUnPaymentCount(array $excepts): int|string
  {
    $this->getModel()->where("service_payment_date > now()");
    $this->getModel()->where("service_status", 'o');
    $this->getModel()->whereNotIn("service_line", $excepts);
    $count =  $this->getModel()->count();
    // echo __FUNCTION__ . ":" . $this->getModel()->getLastQuery();
    return $count;
  }
  //최근신규서비스정보 리스트 limit갯수만큼큼
  public function getLatest(int $limit): array
  {
    $this->getModel()->orderBy($this->getModel()->getPKField(),  'DESC');
    $this->getModel()->limit($limit);
    return $this->getEntities();
  }
  //지역(치바,도쿄등)에 따른 DASHBOARD용 서비스 카운트
  private function getDistrictCountForDashboard(string $where, string $type, array $switchcodes): int
  {
    $switchcode_begin = $switchcodes['begin'];
    $switchcode_end  = $switchcodes['end'];
    $this->getModel()->where($where);
    $this->getModel()->where(["service_line" => $type, "service_status" => 'o']);
    $this->getModel()->where("service_sw BETWEEN '{$switchcode_begin}' AND '$switchcode_end'");
    $count =  $this->getModel()->count();
    // echo "<BR>" . $this->getModel()->getLastQuery();
    return $count;
  }
  final public function getTotalCountForDashboard(array $siteinfo): array
  {
    $temps = array();
    foreach ($siteinfo['totalcount_customers'] as $customer => $where) {
      $temps[$customer] = [];
      foreach ($siteinfo['totalcount_types'] as $type) {
        foreach (DBMS_SERVICE_SWITCHCODE as $district => $switchcodes) {
          $temps[$customer][$type][$district] = $this->getDistrictCountForDashboard($where, $type, $switchcodes);
        }
      } //foreach
      // echo var_dump($temps);
    } //foreach
    return $temps;
  }
  //지역(치바,도쿄등)에 따른 사용자별용 서비스스카운트
  public function getDistrictCountByClient(string $client_code, string $switchcode_begin, string $switchcode_end): int
  {
    $this->getModel()->where("client_code", "{$client_code}");
    $this->getModel()->where("service_sw BETWEEN '{$switchcode_begin}' AND '{$switchcode_end}'");
    $this->getModel()->where("service_status", "o");
    $this->getModel()->whereNotIn("service_line", ['solo', 'test', 'event', 'substitution']);
    return $this->getCount();
    // $sql = "SELECT (SELECT COUNT(*) FROM servicedb WHERE service_line = 'normal' AND service_status = 'o' AND service_sw BETWEEN '{$switchcode_begin}' AND '{$switchcode_end}' AND Client_Code = '{$client_code}') AS normal,
    //               (SELECT COUNT(*) FROM servicedb WHERE service_line = 'defence' AND service_status = 'o' AND service_sw BETWEEN '{$switchcode_begin}' AND '{$switchcode_end}' AND Client_Code = '{$client_code}') AS defence,
    //               (SELECT COUNT(*) FROM servicedb WHERE service_line = 'solo' AND service_status = 'o' AND Client_Code = '{$client_code}') AS solo,
    //               (SELECT COUNT(*) FROM servicedb WHERE service_line = 'test' AND service_status = 'o' AND service_sw BETWEEN '{$switchcode_begin}' AND '{$switchcode_end}' AND Client_Code = '{$client_code}') AS test,
    //               (SELECT COUNT(*) FROM servicedb WHERE service_line = 'event' AND service_status = 'o' AND service_sw BETWEEN '{$switchcode_begin}' AND '{$switchcode_end}' AND Client_Code = '{$client_code}') AS event,
    //               (SELECT COUNT(*) FROM servicedb WHERE service_line = 'substitution' AND service_status = 'o' AND service_sw BETWEEN '{$switchcode_begin}' AND '{$switchcode_end}' AND Client_Code = '{$client_code}') AS substitution";
    // $stmt = $this->getModel()->execute($sql);
    // // echo "<BR>" . $this->getModel()->getLastQuery();
    // return $stmt->fetch(PDO::FETCH_ASSOC);
  }
  //ServieLine(일반,방어,전용,테스트,대체등)에 따른 사용자별용 서비스 카운트
  public function getServiceLineCountByClient(string $client_code, string $service_line): int
  {
    $this->getModel()->where("client_code", "{$client_code}");
    $this->getModel()->where("service_line", "{$service_line}");
    $this->getModel()->where("service_status", 'o');
    return $this->getCount();
  }
  //사용자별용 서비스 쿠폰 카운트
  public function getCouponTotalCountByClient(string $client_code): int
  {
    $this->getModel()->where("client_code", "{$client_code}");
    $this->getModel()->whereNotIn("service_line", ['vpn', 'test', 'solo', 'substitution', 'event']);
    return $this->getCount("SUM(coupon) as cnt");
  }
  //도메인쿠폰 사용용
  public function useCouponForDomain(ServiceEntity $service, int $coupon): bool
  {
    if ($coupon < 0) {
      throw new \Exception("쿠폰수량이 잘못되었습니다. 쿠폰수량 : $coupon");
    }
    $this->getModel()->where("service_code", $service->getServiceCode());
    $this->getModel()->update(["coupon=(coupon-{$coupon})" => null, "coupon_use=(coupon_use+{$coupon})" => null]);
    return true;
  } //setCoupon
  public function resetCouponByClient(ClientEntity $client, int $coupon): bool
  {
    if ($coupon < 0) {
      throw new \Exception("쿠폰수량이 잘못되었습니다. 쿠폰수량 : $coupon");
    }
    $this->getModel()->where("client_code", $client->getClientCode());
    $this->getModel()->where("server_code", $client->getTitle() . "_일회성");
    $this->getModel()->update(["coupon" => $coupon, "coupon_use" => 0]);
    return true;
  } //setCoupon
}
