<?php

namespace App\Controllers;

use App\Libraries\TemporaryImageUpload;
use App\Models\TeknisiModel;
use Config\Database;
use RuntimeException;

class TeknisiController extends BaseController
{
    private TeknisiModel $teknisiModel;
    private TemporaryImageUpload $temporaryImageUpload;
    private string $uploadPath;

    public function __construct()
    {
        $this->teknisiModel         = new TeknisiModel();
        $this->temporaryImageUpload = new TemporaryImageUpload();
        $this->uploadPath           = FCPATH . 'uploads/teknisi';
    }

    public function index()
    {
        if (! $this->isLoggedIn()) {
            return redirect()->to('/login')->with('error', 'Silakan login terlebih dahulu.');
        }

        if ($redirect = $this->requireAdministrator('/admin/dashboard', 'Akses ditolak. Data teknisi hanya dapat diakses oleh administrator.')) {
            return $redirect;
        }

        $teknisi = $this->teknisiModel
            ->select('teknisi.*')
            ->select('(SELECT COUNT(*) FROM service WHERE service.teknisi_id = teknisi.id) AS total_service', false)
            ->orderBy('id', 'DESC')
            ->findAll();

        return view('admin/teknisi/index', [
            'teknisi'   => $teknisi,
            'userName'  => session()->get('userName'),
            'userEmail' => session()->get('userEmail'),
            'userRole'  => session()->get('userRole'),
        ]);
    }

    public function create()
    {
        if (! $this->isLoggedIn()) {
            return redirect()->to('/login')->with('error', 'Silakan login terlebih dahulu.');
        }

        if ($redirect = $this->requireAdministrator('/admin/teknisi')) {
            return $redirect;
        }

        return view('admin/teknisi/create', [
            'kodeTeknisi' => $this->nextCode('teknisi', 'kode_teknisi', 'TEK'),
            'userName'    => session()->get('userName'),
            'userEmail'   => session()->get('userEmail'),
            'userRole'    => session()->get('userRole'),
        ]);
    }

    public function store()
    {
        if (! $this->isLoggedIn()) {
            return redirect()->to('/login')->with('error', 'Silakan login terlebih dahulu.');
        }

        if ($redirect = $this->requireAdministrator('/admin/teknisi')) {
            return $redirect;
        }

        if (! $this->validate($this->validationRules())) {
            return redirect()->back()->withInput()->with('errors', $this->validator->getErrors());
        }

        try {
            $foto = $this->moveTemporaryPhoto();
        } catch (RuntimeException $exception) {
            return redirect()->back()->withInput()->with('errors', [
                'foto' => $exception->getMessage(),
            ]);
        }

        $data = $this->formData();
        $data['foto'] = $foto;
        $data['kode_teknisi'] = $this->nextCode('teknisi', 'kode_teknisi', 'TEK');

        $this->teknisiModel->insert($data);

        return redirect()->to('/admin/teknisi')->with('success', 'Data teknisi berhasil ditambahkan.');
    }

    public function edit(int $id)
    {
        if (! $this->isLoggedIn()) {
            return redirect()->to('/login')->with('error', 'Silakan login terlebih dahulu.');
        }

        if ($redirect = $this->requireAdministrator('/admin/teknisi')) {
            return $redirect;
        }

        $teknisi = $this->teknisiModel->find($id);

        if (! $teknisi) {
            return redirect()->to('/admin/teknisi')->with('error', 'Data teknisi tidak ditemukan.');
        }

        return view('admin/teknisi/edit', [
            'teknisi'   => $teknisi,
            'userName'  => session()->get('userName'),
            'userEmail' => session()->get('userEmail'),
            'userRole'  => session()->get('userRole'),
        ]);
    }

    public function update(int $id)
    {
        if (! $this->isLoggedIn()) {
            return redirect()->to('/login')->with('error', 'Silakan login terlebih dahulu.');
        }

        if ($redirect = $this->requireAdministrator('/admin/teknisi')) {
            return $redirect;
        }

        $teknisi = $this->teknisiModel->find($id);

        if (! $teknisi) {
            return redirect()->to('/admin/teknisi')->with('error', 'Data teknisi tidak ditemukan.');
        }

        if (! $this->validate($this->validationRules())) {
            return redirect()->back()->withInput()->with('errors', $this->validator->getErrors());
        }

        $data = $this->formData();

        try {
            $foto = $this->moveTemporaryPhoto();
        } catch (RuntimeException $exception) {
            return redirect()->back()->withInput()->with('errors', [
                'foto' => $exception->getMessage(),
            ]);
        }

        if ($foto !== null) {
            $data['foto'] = $foto;
            $this->deletePhoto($teknisi['foto'] ?? null);
        }

        $this->teknisiModel->update($id, $data);

        return redirect()->to('/admin/teknisi')->with('success', 'Data teknisi berhasil diperbarui.');
    }

    public function delete(int $id)
    {
        if (! $this->isLoggedIn()) {
            return redirect()->to('/login')->with('error', 'Silakan login terlebih dahulu.');
        }

        if ($redirect = $this->requireAdministrator('/admin/teknisi')) {
            return $redirect;
        }

        $teknisi = $this->teknisiModel->find($id);

        if (! $teknisi) {
            return redirect()->to('/admin/teknisi')->with('error', 'Data teknisi tidak ditemukan.');
        }

        if ($this->totalServiceByTeknisi($id) > 0) {
            return redirect()->to('/admin/teknisi')->with(
                'error',
                'Data teknisi tidak dapat dihapus karena sudah terhubung ke transaksi service.'
            );
        }

        $this->teknisiModel->delete($id);
        $this->deletePhoto($teknisi['foto'] ?? null);

        return redirect()->to('/admin/teknisi')->with('success', 'Data teknisi berhasil dihapus.');
    }

    private function validationRules(): array
    {
        return [
            'nama'   => 'required|min_length[1]|max_length[100]',
            'no_hp'  => 'required|min_length[8]|max_length[30]|regex_match[/^[0-9+().\\-\\s]+$/]',            
        ];
    }

    private function formData(): array
    {
        return [
            'nama'   => $this->request->getPost('nama'),
            'no_hp'  => $this->request->getPost('no_hp'),
            'alamat' => $this->request->getPost('alamat'),
        ];
    }

    private function moveTemporaryPhoto(): ?string
    {
        return $this->temporaryImageUpload->moveToPermanent(
            $this->request->getPost('foto_temp'),
            $this->uploadPath,
            ['jpg', 'jpeg', 'png', 'webp']
        );
    }

    private function deletePhoto(?string $photoName): void
    {
        if (! $photoName) {
            return;
        }

        $photoPath = $this->uploadPath . DIRECTORY_SEPARATOR . $photoName;

        if (is_file($photoPath)) {
            unlink($photoPath);
        }
    }

    private function nextCode(string $table, string $field, string $prefix): string
    {
        $row = Database::connect()
            ->table($table)
            ->select("MAX(CAST(SUBSTRING({$field}, 4) AS UNSIGNED)) AS last_number", false)
            ->get()
            ->getRowArray();

        return $prefix . str_pad((string) (((int) ($row['last_number'] ?? 0)) + 1), 4, '0', STR_PAD_LEFT);
    }

    private function totalServiceByTeknisi(int $teknisiId): int
    {
        return Database::connect()
            ->table('service')
            ->where('teknisi_id', $teknisiId)
            ->countAllResults();
    }

    private function isLoggedIn(): bool
    {
        return (bool) session()->get('isLoggedIn') && $this->isUserAccount();
    }
}
