<?php

namespace App\Services;

use App\Models\ActivityLogModel;
use App\Models\CompanySettingsModel;
use CodeIgniter\HTTP\Files\UploadedFile;
use Config\Uploads;

class CompanySettingsService
{
    protected CompanySettingsModel $settings;
    protected ActivityLogModel $activity;
    protected Uploads $uploadsConfig;

    public function __construct()
    {
        $this->settings      = new CompanySettingsModel();
        $this->activity      = new ActivityLogModel();
        $this->uploadsConfig = config('Uploads');
    }

    public function get(): array
    {
        return $this->settings->getSettings();
    }

    /**
     * @return array<string, array{label: string, symbol: string, decimals: int}>
     */
    public function supportedCurrencies(): array
    {
        return [
            'BHD' => ['label' => 'Bahraini Dinar', 'symbol' => 'BD', 'decimals' => 3],
            'SAR' => ['label' => 'Saudi Riyal', 'symbol' => 'SR', 'decimals' => 2],
            'AED' => ['label' => 'UAE Dirham', 'symbol' => 'AED', 'decimals' => 2],
            'KWD' => ['label' => 'Kuwaiti Dinar', 'symbol' => 'KD', 'decimals' => 3],
            'OMR' => ['label' => 'Omani Rial', 'symbol' => 'OMR', 'decimals' => 3],
            'QAR' => ['label' => 'Qatari Riyal', 'symbol' => 'QR', 'decimals' => 2],
            'USD' => ['label' => 'US Dollar', 'symbol' => '$', 'decimals' => 2],
            'EUR' => ['label' => 'Euro', 'symbol' => '€', 'decimals' => 2],
            'GBP' => ['label' => 'British Pound', 'symbol' => '£', 'decimals' => 2],
            'INR' => ['label' => 'Indian Rupee', 'symbol' => '₹', 'decimals' => 2],
        ];
    }

    /**
     * @return array<string, string>
     */
    public function dateFormats(): array
    {
        return [
            'd/m/Y' => '31/12/2026 (DD/MM/YYYY)',
            'm/d/Y' => '12/31/2026 (MM/DD/YYYY)',
            'Y-m-d' => '2026-12-31 (YYYY-MM-DD)',
            'd-M-Y' => '31-Dec-2026',
        ];
    }

    /**
     * @return array<string, string>
     */
    public function locales(): array
    {
        return [
            'en_BH' => 'English (Bahrain)',
            'ar_BH' => 'Arabic (Bahrain)',
            'en_US' => 'English (US)',
            'en_GB' => 'English (UK)',
            'ar_SA' => 'Arabic (Saudi Arabia)',
            'ar_AE' => 'Arabic (UAE)',
        ];
    }

    /**
     * @return array<string, string>
     */
    public function fiscalMonths(): array
    {
        return [
            1  => 'January',
            2  => 'February',
            3  => 'March',
            4  => 'April',
            5  => 'May',
            6  => 'June',
            7  => 'July',
            8  => 'August',
            9  => 'September',
            10 => 'October',
            11 => 'November',
            12 => 'December',
        ];
    }

    /**
     * @return array<string, string>
     */
    public function timezones(): array
    {
        $zones = [
            'Asia/Bahrain'  => 'Asia/Bahrain (GMT+3)',
            'Asia/Riyadh'   => 'Asia/Riyadh (GMT+3)',
            'Asia/Dubai'    => 'Asia/Dubai (GMT+4)',
            'Asia/Kuwait'   => 'Asia/Kuwait (GMT+3)',
            'Asia/Muscat'   => 'Asia/Muscat (GMT+4)',
            'Asia/Qatar'    => 'Asia/Qatar (GMT+3)',
            'Asia/Kolkata'  => 'Asia/Kolkata (GMT+5:30)',
            'Europe/London' => 'Europe/London',
            'Europe/Paris'  => 'Europe/Paris',
            'America/New_York' => 'America/New_York',
            'UTC'           => 'UTC',
        ];

        return $zones;
    }

    public function update(array $input, ?int $actingUserId): array
    {
        $company    = $this->settings->getSettings();
        $currencies = $this->supportedCurrencies();
        $currencyCode = strtoupper(trim((string) ($input['currency_code'] ?? 'BHD')));

        if (! isset($currencies[$currencyCode])) {
            return ['success' => false, 'errors' => ['currency_code' => 'Please select a valid currency.']];
        }

        $currency    = $currencies[$currencyCode];
        $fiscalMonth = (int) ($input['fiscal_year_start_month'] ?? 1);
        if ($fiscalMonth < 1 || $fiscalMonth > 12) {
            $fiscalMonth = 1;
        }

        $data = [
            'name'                    => trim((string) $input['name']),
            'legal_name'              => $this->nullableString($input['legal_name'] ?? null),
            'currency_code'           => $currencyCode,
            'currency_symbol'         => $currency['symbol'],
            'decimal_places'          => $currency['decimals'],
            'address'                 => $this->nullableString($input['address'] ?? null),
            'city'                    => $this->nullableString($input['city'] ?? null),
            'country'                 => $this->nullableString($input['country'] ?? null),
            'postal_code'             => $this->nullableString($input['postal_code'] ?? null),
            'phone'                   => $this->nullableString($input['phone'] ?? null),
            'email'                   => $this->nullableString($input['email'] ?? null),
            'website'                 => $this->nullableString($input['website'] ?? null),
            'tax_id'                  => $this->nullableString($input['tax_id'] ?? null),
            'commercial_registration' => $this->nullableString($input['commercial_registration'] ?? null),
            'timezone'                => trim((string) ($input['timezone'] ?? 'Asia/Bahrain')),
            'locale'                  => trim((string) ($input['locale'] ?? 'en_BH')),
            'date_format'             => trim((string) ($input['date_format'] ?? 'd/m/Y')),
            'fiscal_year_start_month' => $fiscalMonth,
        ];

        if (! $this->settings->update($company['id'], $data)) {
            return ['success' => false, 'errors' => $this->settings->errors()];
        }

        $this->activity->log('company', 'updated', $actingUserId, 'Updated company settings');

        return ['success' => true];
    }

    /**
     * @return array{success: bool, errors?: array<string, string>}
     */
    public function updateSecurity(array $input, ?int $actingUserId): array
    {
        $company = $this->settings->getSettings();

        $maxFailed = (int) ($input['tpin_max_failed_attempts'] ?? 5);
        $lockout   = (int) ($input['tpin_lockout_minutes'] ?? 15);

        if ($maxFailed < 3 || $maxFailed > 10) {
            return ['success' => false, 'errors' => ['tpin_max_failed_attempts' => 'Max failed attempts must be between 3 and 10.']];
        }

        if ($lockout < 5 || $lockout > 60) {
            return ['success' => false, 'errors' => ['tpin_lockout_minutes' => 'Lockout duration must be between 5 and 60 minutes.']];
        }

        $data = [
            'tpin_enabled'             => ! empty($input['tpin_enabled']) ? 1 : 0,
            'tpin_required_by_default' => ! empty($input['tpin_required_by_default']) ? 1 : 0,
            'tpin_max_failed_attempts' => $maxFailed,
            'tpin_lockout_minutes'     => $lockout,
        ];

        if (! $this->settings->update($company['id'], $data)) {
            return ['success' => false, 'errors' => $this->settings->errors()];
        }

        $this->activity->log('company', 'security_updated', $actingUserId, 'Updated company security settings');

        return ['success' => true];
    }

    public function uploadLogo(UploadedFile $file, ?int $actingUserId): array
    {
        if (! $file->isValid() || $file->hasMoved()) {
            return ['success' => false, 'error' => 'Upload failed. Please try again.'];
        }

        if (! in_array($file->getMimeType(), $this->uploadsConfig->logoAllowedMimes, true)) {
            return ['success' => false, 'error' => 'Only JPEG, PNG or WEBP images are allowed.'];
        }

        if ($file->getSizeByUnit('kb') > $this->uploadsConfig->logoMaxSizeKB) {
            return ['success' => false, 'error' => 'Image must be smaller than ' . $this->uploadsConfig->logoMaxSizeKB . 'KB.'];
        }

        $company = $this->settings->getSettings();
        $newName = $file->getRandomName();

        if (! is_dir($this->uploadsConfig->logoUploadPath)) {
            mkdir($this->uploadsConfig->logoUploadPath, 0755, true);
        }

        $file->move($this->uploadsConfig->logoUploadPath, $newName);

        $relativePath = rtrim($this->uploadsConfig->logoPublicPath, '/') . '/' . $newName;

        if (! empty($company['logo_path'])) {
            $oldPath = FCPATH . $company['logo_path'];
            if (is_file($oldPath)) {
                @unlink($oldPath);
            }
        }

        $this->settings->update($company['id'], ['logo_path' => $relativePath]);
        $this->activity->log('company', 'logo_updated', $actingUserId, 'Updated company logo');

        return ['success' => true, 'path' => $relativePath];
    }

    public function removeLogo(?int $actingUserId): array
    {
        $company = $this->settings->getSettings();

        if (! empty($company['logo_path'])) {
            $oldPath = FCPATH . $company['logo_path'];
            if (is_file($oldPath)) {
                @unlink($oldPath);
            }
        }

        $this->settings->update($company['id'], ['logo_path' => null]);
        $this->activity->log('company', 'logo_removed', $actingUserId, 'Removed company logo');

        return ['success' => true];
    }

    private function nullableString(?string $value): ?string
    {
        $value = trim((string) $value);

        return $value === '' ? null : $value;
    }
}
