<?php

namespace App\Repositories;

use PDO;
use App\Config\DatasourceConfig;
use App\Helpers\UserMapper;
use App\Interfaces\UserRequest;

final class UserRepo
{

  private PDO $connection;
  private UserMapper $userMapper;

  public function __construct()
  {
    $this->connection = (new DatasourceConfig())->connect();
    $this->userMapper = new UserMapper();
  }

  private string $querySelect = "
    SELECT 
      usr.id_user as id,
      usr.nama as nama,
      usr.username as username,
      usr.password as password,
      usr.email as email,
      usr.no_telepon as noTelepon,
      usr.role as role,
      usr.id_divisi as divisiId,
      usr.status_akun as statusAkun,
      usr.created_at as createdAt,
      usr.updated_at as updatedAt,
      divisi.nama_divisi as namaDivisi,
      teknisi.spesialisasi as spesialisasi
    FROM users usr
    LEFT JOIN divisions divisi
    ON usr.id_divisi = divisi.id_divisi
    LEFT JOIN teknisi
    ON usr.id_user = teknisi.id_user
  ";

  public function findAll()
  {

    $statement = $this->connection->prepare($this->querySelect);
    $statement->execute();
    $rows = $statement->fetchAll(PDO::FETCH_ASSOC);

    $users = array_map([$this->userMapper, 'toUser'], $rows);

    return $users;
  }

  public function findById(int $id)
  {
    $statement = $this->connection->prepare($this->querySelect . " WHERE usr.id_user = :id");
    $statement->execute(['id' => $id]);
    $row = $statement->fetch(PDO::FETCH_ASSOC);

    if (!$row) {
      return null;
    }

    return $this->userMapper->toUser($row);
  }

  public function findBy(?string $keyword, ?string $role, ?string $divisi, ?string $statusAkun)
  {
    $querySearch = $this->querySelect . "

      WHERE
      (
        (:keywordNull IS NULL OR :keywordNull = '')
        OR usr.nama LIKE CONCAT('%', :keyword, '%')
        OR usr.username LIKE CONCAT('%', :keyword, '%')
      )
      AND ((:roleNull IS NULL OR :roleNull = '') OR usr.role = :role)
      AND ((:divisiNull IS NULL OR :divisiNull = '') OR divisi.nama_divisi = :divisi)
      AND ((:statusNull IS NULL OR :statusNull = '')OR usr.status_akun = :status)
    ";

    $statement = $this->connection->prepare($querySearch);

    $statement->execute([
      'keywordNull' => $keyword ?? null,
      'keyword' => $keyword,

      'roleNull' => $role ?? null,
      'role' => $role,

      'divisiNull' => $divisi ?? null,
      'divisi' => $divisi ?? null,

      'statusNull' => $statusAkun ?? null,
      'status' => $statusAkun,
    ]);

    $rows = $statement->fetchAll(PDO::FETCH_ASSOC);

    $users = array_map([$this->userMapper, 'toUser'], $rows);

    return $users;
  }

  public function save(
    UserRequest $request
  ): void {
    $query = "INSERT INTO users
      (nama, username, password, email, no_telepon, `role`, id_divisi, status_akun)
      VALUES(:nama, :username, :password, :email, :no_telepon, :role, :id_divisi, :status_akun);";

    $statement = $this->connection->prepare($query);
    $statement->execute($this->userMapper->toArray($request));
  }

  public function update(
    UserRequest $request
  ): void {
    $query = "UPDATE users
      SET nama=:nama,
      username=:username,
      email=:email,
      no_telepon=:no_telepon,
      `role`=:role,
      id_divisi=:id_divisi,
      status_akun=:status_akun
      WHERE id_user=:id_user;";

    $statement = $this->connection->prepare($query);
    $statement->execute($this->userMapper->toArray($request, false));
  }

  public function changePassword(
    string $id,
    string $password
  ): void {

    $query = "UPDATE users
      SET password=:password
      WHERE id_user=:id_user;";

    $statement = $this->connection->prepare($query);
    $statement->execute([
      'password' => $password,
      'id_user' => $id,
    ]);
  }

  public function getByEmail(string $email)
  {

    $queryStr = $this->querySelect . " WHERE email = :email";

    $statement = $this->connection->prepare($queryStr);
    $statement->execute([
      'email' => $email
    ]);
    $row = $statement->fetch(PDO::FETCH_ASSOC);

    if (!$row) {
      return null;
    }

    return $this->userMapper->toUser($row);
  }

  // get by username
  public function getByUsername(string $username)
  {

    $queryStr = $this->querySelect . " WHERE username = :username";

    $statement = $this->connection->prepare($queryStr);
    $statement->execute([
      'username' => $username
    ]);
    $row = $statement->fetch(PDO::FETCH_ASSOC);

    if (!$row) {
      return null;
    }

    return $this->userMapper->toUser($row);
  }
}
