<?php

namespace App\Controllers;

use App\Models\PelangganModel;
use Config\Database;

class PelangganController extends BaseController
{
    private PelangganModel $pelangganModel;

    public function __construct()
    {
        $this->pelangganModel = new PelangganModel();
    }

    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 pelanggan hanya dapat diakses oleh administrator.')) {
            return $redirect;
        }

        $pelanggan = $this->pelangganModel
            ->select('pelanggan.*')
            ->select('(SELECT COUNT(*) FROM penjualan WHERE penjualan.pelanggan_id = pelanggan.id) AS total_penjualan', false)
            ->select('(SELECT COUNT(*) FROM service WHERE service.pelanggan_id = pelanggan.id) AS total_service', false)
            ->orderBy('id', 'DESC')
            ->findAll();

        return view('admin/pelanggan/index', [
            'pelanggan' => $pelanggan,
            '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/pelanggan')) {
            return $redirect;
        }

        return view('admin/pelanggan/create', [
            'kodePelanggan' => $this->nextCode('pelanggan', 'kode_pelanggan', 'CUS'),
            '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/pelanggan')) {
            return $redirect;
        }

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

        $data = $this->formData();
        $data['kode_pelanggan'] = $this->nextCode('pelanggan', 'kode_pelanggan', 'CUS');

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

        return redirect()->to('/admin/pelanggan')->with('success', 'Data pelanggan 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/pelanggan')) {
            return $redirect;
        }

        $pelanggan = $this->pelangganModel->find($id);

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

        return view('admin/pelanggan/edit', [
            'pelanggan' => $pelanggan,
            '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/pelanggan')) {
            return $redirect;
        }

        $pelanggan = $this->pelangganModel->find($id);

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

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

        $this->pelangganModel->update($id, $this->formData());

        return redirect()->to('/admin/pelanggan')->with('success', 'Data pelanggan 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/pelanggan')) {
            return $redirect;
        }

        $pelanggan = $this->pelangganModel->find($id);

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

        $usage = $this->pelangganUsage($id);

        if (array_sum($usage) > 0) {
            return redirect()->to('/admin/pelanggan')->with(
                'error',
                'Data pelanggan tidak dapat dihapus karena sudah terhubung ke transaksi penjualan atau service.'
            );
        }

        $this->pelangganModel->delete($id);

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

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

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

    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 pelangganUsage(int $pelangganId): array
    {
        $db = Database::connect();

        return [
            'penjualan' => $db->table('penjualan')->where('pelanggan_id', $pelangganId)->countAllResults(),
            'service'   => $db->table('service')->where('pelanggan_id', $pelangganId)->countAllResults(),
        ];
    }

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