<?php
declare(strict_types=1);

namespace App\Modules\Admin;

use App\Core\AuditLogger;
use App\Core\Auth;
use App\Core\Request;
use App\Core\Settings;
use App\Core\Session;
use App\Core\View;

final class AdminSettingController
{
    public function index(Request $request): string
    {
        require_role('admin');

        return View::renderTemplate('admin/settings', [
            'settings' => $this->currentSettings(),
        ], 'admin/layout');
    }

    public function update(Request $request): never
    {
        require_role('admin');
        verify_csrf((string) $request->input('_token', ''));

        $current = $this->currentSettings();
        $companyName = trim((string) $request->input('company_name', ''));
        $bankAccountNumber = preg_replace('/\s+/', '', trim((string) $request->input('bank_account_number', '')));

        $errors = [];

        if ($companyName === '' || mb_strlen($companyName) < 3 || mb_strlen($companyName) > 120) {
            $errors['company_name'][] = 'Nama perusahaan wajib diisi antara 3 sampai 120 karakter.';
        }

        if ($bankAccountNumber === '' || ! preg_match('/^[0-9]{6,30}$/', $bankAccountNumber)) {
            $errors['bank_account_number'][] = 'Nomor rekening harus berupa angka 6-30 digit.';
        }

        $logoPath = $current['company_logo'];
        $barcodePath = $current['payment_barcode'];

        $logoFile = $_FILES['company_logo'] ?? null;
        if (is_array($logoFile) && (($logoFile['error'] ?? UPLOAD_ERR_NO_FILE) !== UPLOAD_ERR_NO_FILE)) {
            $validated = $this->validateImageUpload($logoFile, ['jpg', 'jpeg', 'png'], 2 * 1024 * 1024);
            if ($validated['error'] !== null) {
                $errors['company_logo'][] = $validated['error'];
            } else {
                $logoPath = $this->storeUpload($logoFile, 'company-logo');
            }
        }

        $barcodeFile = $_FILES['payment_barcode'] ?? null;
        if (is_array($barcodeFile) && (($barcodeFile['error'] ?? UPLOAD_ERR_NO_FILE) !== UPLOAD_ERR_NO_FILE)) {
            $validated = $this->validateImageUpload($barcodeFile, ['jpg', 'jpeg'], 2 * 1024 * 1024);
            if ($validated['error'] !== null) {
                $errors['payment_barcode'][] = $validated['error'];
            } else {
                $barcodePath = $this->storeUpload($barcodeFile, 'payment-barcode');
            }
        }

        Session::flash('old_input', [
            'company_name' => $companyName,
            'bank_account_number' => $bankAccountNumber,
        ]);

        if ($errors !== []) {
            Session::flash('errors', $errors);
            redirect('/admin/settings');
        }

        Settings::setMany([
            'company_name' => $companyName,
            'bank_account_number' => $bankAccountNumber,
            'company_logo' => $logoPath,
            'payment_barcode' => $barcodePath,
        ]);

        AuditLogger::log('admin_settings_update', Auth::id(), [
            'company_name' => $companyName,
            'bank_account_number' => $bankAccountNumber,
            'company_logo' => $logoPath,
            'payment_barcode' => $barcodePath,
        ]);

        Session::flash('status', 'Pengaturan perusahaan berhasil disimpan.');
        redirect('/admin/settings');
    }

    private function currentSettings(): array
    {
        return [
            'company_name' => (string) Settings::get('company_name', app_name()),
            'company_logo' => Settings::get('company_logo'),
            'bank_account_number' => (string) Settings::get('bank_account_number', ''),
            'payment_barcode' => Settings::get('payment_barcode'),
        ];
    }

    private function validateImageUpload(array $file, array $allowedExtensions, int $maxBytes): array
    {
        $error = (int) ($file['error'] ?? UPLOAD_ERR_NO_FILE);
        if ($error !== UPLOAD_ERR_OK) {
            return ['error' => 'Gagal mengunggah file.', 'extension' => null];
        }

        $tmpName = (string) ($file['tmp_name'] ?? '');
        if ($tmpName === '' || ! is_uploaded_file($tmpName)) {
            return ['error' => 'File upload tidak valid.', 'extension' => null];
        }

        $size = (int) ($file['size'] ?? 0);
        if ($size <= 0) {
            return ['error' => 'File tidak boleh kosong.', 'extension' => null];
        }

        if ($size > $maxBytes) {
            return ['error' => 'Ukuran file maksimal 2 MB.', 'extension' => null];
        }

        $originalName = (string) ($file['name'] ?? '');
        $extension = strtolower(pathinfo($originalName, PATHINFO_EXTENSION));
        if (! in_array($extension, $allowedExtensions, true)) {
            return ['error' => 'Format file tidak didukung.', 'extension' => null];
        }

        $finfo = finfo_open(FILEINFO_MIME_TYPE);
        if ($finfo === false) {
            return ['error' => 'Tidak dapat memeriksa tipe file.', 'extension' => null];
        }

        $mime = finfo_file($finfo, $tmpName);
        finfo_close($finfo);

        $allowedMime = [
            'jpg' => ['image/jpeg', 'image/pjpeg'],
            'jpeg' => ['image/jpeg', 'image/pjpeg'],
            'png' => ['image/png'],
        ];

        foreach ($allowedExtensions as $ext) {
            if (! isset($allowedMime[$ext])) {
                continue;
            }

            if (is_string($mime) && in_array($mime, $allowedMime[$ext], true)) {
                return ['error' => null, 'extension' => $extension === 'jpeg' ? 'jpg' : $extension];
            }
        }

        return ['error' => 'Tipe file tidak valid.', 'extension' => null];
    }

    private function storeUpload(array $file, string $prefix): string
    {
        $originalName = (string) ($file['name'] ?? '');
        $extension = strtolower(pathinfo($originalName, PATHINFO_EXTENSION));
        if ($extension === 'jpeg') {
            $extension = 'jpg';
        }

        $directory = dirname(__DIR__, 3) . '/storage/uploads/settings';
        if (! is_dir($directory)) {
            mkdir($directory, 0775, true);
        }

        $filename = $prefix . '-' . bin2hex(random_bytes(16)) . '.' . $extension;
        $targetPath = $directory . '/' . $filename;

        if (! move_uploaded_file((string) $file['tmp_name'], $targetPath)) {
            abort(500, 'Gagal menyimpan file upload.');
        }

        return 'storage/uploads/settings/' . $filename;
    }
}
