<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Models\Business;
use App\Models\Setting;
use App\Services\AuditService;
use App\Services\ModuleManager;
use App\Services\SmsGatewayService;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Validation\Rule;
use Illuminate\View\View;
use RuntimeException;

class SystemSettingController extends Controller
{
    public function edit(ModuleManager $modules): View
    {
        $business = Business::firstOrCreate(['id' => 1], ['name' => 'Microfinance']);
        $settings = Setting::where('business_id', $business->id)->pluck('value', 'key');
        $smsApiKeyConfigured = filled($settings->get('sms_api_key') ?: $settings->get('sms_bearer_token'));
        $settings->forget(['sms_api_key', 'sms_bearer_token']);
        $whatsappTokenConfigured = filled($business->whatsapp_api_token);
        $moduleSettings = $modules->all($business->id);

        return view('admin.settings.system', compact(
            'business',
            'settings',
            'moduleSettings',
            'smsApiKeyConfigured',
            'whatsappTokenConfigured',
        ));
    }

    public function update(Request $request): RedirectResponse
    {
        $business = Business::firstOrCreate(['id' => 1], ['name' => 'Microfinance']);
        $existingSmsCredentials = Setting::query()
            ->where('business_id', $business->id)
            ->where('group', 'sms')
            ->whereIn('key', ['sms_api_key', 'sms_bearer_token'])
            ->pluck('value', 'key');
        $existingSmsApiKey = $existingSmsCredentials->get('sms_api_key') ?: $existingSmsCredentials->get('sms_bearer_token');

        $smsSettingsPresent = $request->boolean('sms_settings_present');
        $smsEnabled = $request->boolean('sms_enabled');
        $identitySettingsPresent = $request->boolean('identity_settings_present');
        $ninLookupEnabled = $request->boolean('nin_lookup_enabled');

        $data = $request->validate([
            'timezone' => ['required', 'timezone'],
            'date_format' => ['required', Rule::in(['d/m/Y', 'Y-m-d', 'd M Y'])],
            'session_timeout_minutes' => ['required', 'integer', 'between:5,1440'],
            'require_2fa' => ['nullable', 'boolean'],
            'modules_present' => ['nullable', 'boolean'],
            'modules' => ['nullable', 'array'],
            'modules.*' => ['nullable', 'boolean'],
            'identity_settings_present' => ['nullable', 'boolean'],
            'nin_lookup_enabled' => ['nullable', 'boolean'],
            'nida_api_url' => ['nullable', 'url', 'starts_with:https://', 'max:2048'],
            'sms_settings_present' => ['nullable', 'boolean'],
            'sms_enabled' => ['nullable', 'boolean'],
            'sms_api_url' => [
                Rule::requiredIf(fn (): bool => $smsSettingsPresent && $smsEnabled),
                'nullable',
                'url',
                'max:2048',
            ],
            'sms_sender_id' => [
                Rule::requiredIf(fn (): bool => $smsSettingsPresent && $smsEnabled),
                'nullable',
                'string',
                'max:64',
            ],
            'sms_api_key' => [
                Rule::requiredIf(fn (): bool => $smsSettingsPresent && $smsEnabled && blank($existingSmsApiKey)),
                'nullable',
                'string',
                'max:4096',
            ],
            'sms_timeout_seconds' => ['nullable', 'integer', 'between:3,60'],
        ]);
        $data['require_2fa'] = $request->boolean('require_2fa') ? '1' : '0';

        $systemValues = collect($data)->only(['timezone','date_format','session_timeout_minutes','require_2fa'])->all();
        foreach ($systemValues as $key => $value) {
            Setting::updateOrCreate(
                ['business_id' => $business->id, 'group' => 'system', 'key' => $key],
                ['value' => (string) $value, 'type' => in_array($key, ['session_timeout_minutes', 'require_2fa'], true) ? 'integer' : 'string'],
            );
        }

        $identityAuditValues = [];
        if ($identitySettingsPresent) {
            $nidaApiUrl = rtrim(trim((string) ($data['nida_api_url'] ?? '')), '/');

            Setting::updateOrCreate(
                ['business_id' => $business->id, 'group' => 'identity', 'key' => 'nin_lookup_enabled'],
                ['value' => $ninLookupEnabled ? '1' : '0', 'type' => 'boolean'],
            );
            Setting::updateOrCreate(
                ['business_id' => $business->id, 'group' => 'identity', 'key' => 'nida_api_url'],
                ['value' => $nidaApiUrl, 'type' => 'string'],
            );

            $identityAuditValues = [
                'nin_lookup_enabled' => $ninLookupEnabled,
                'nida_api_url' => $nidaApiUrl,
            ];
        }

        $moduleValues = [];
        if ($request->boolean('modules_present')) {
            foreach (ModuleManager::MODULES as $key => $definition) {
                $enabled = $request->boolean('modules.'.$key);
                $moduleValues[$key] = $enabled;
                Setting::updateOrCreate(
                    ['business_id' => $business->id, 'group' => 'modules', 'key' => $key],
                    ['value' => $enabled ? '1' : '0', 'type' => 'boolean'],
                );
            }
        }

        $smsAuditValues = [];
        if ($smsSettingsPresent) {
            $smsValues = [
                'sms_enabled' => [$smsEnabled ? '1' : '0', 'boolean'],
                'sms_api_url' => [trim((string) ($data['sms_api_url'] ?? '')), 'string'],
                'sms_sender_id' => [trim((string) ($data['sms_sender_id'] ?? '')), 'string'],
                'sms_timeout_seconds' => [(string) ($data['sms_timeout_seconds'] ?? 15), 'integer'],
            ];

            foreach ($smsValues as $key => [$value, $type]) {
                Setting::updateOrCreate(
                    ['business_id' => $business->id, 'group' => 'sms', 'key' => $key],
                    ['value' => $value, 'type' => $type],
                );
            }

            $apiKeyUpdated = filled($data['sms_api_key'] ?? null);
            if ($apiKeyUpdated) {
                Setting::updateOrCreate(
                    ['business_id' => $business->id, 'group' => 'sms', 'key' => 'sms_api_key'],
                    ['value' => Crypt::encryptString((string) $data['sms_api_key']), 'type' => 'encrypted'],
                );

                Setting::query()
                    ->where('business_id', $business->id)
                    ->where('group', 'sms')
                    ->where('key', 'sms_bearer_token')
                    ->delete();
            }

            $smsAuditValues = [
                'enabled' => $smsEnabled,
                'api_url' => $smsValues['sms_api_url'][0],
                'sender_id' => $smsValues['sms_sender_id'][0],
                'timeout_seconds' => (int) $smsValues['sms_timeout_seconds'][0],
                'api_key_updated' => $apiKeyUpdated,
            ];
        }

        AuditService::record('system.settings.updated', $business, [], [
            'system' => $systemValues,
            'identity' => $identityAuditValues,
            'modules' => $moduleValues,
            'sms' => $smsAuditValues,
        ]);

        return back()->with('success', 'System settings, NIN verification, module availability and SMS configuration updated.');
    }

    public function testSms(Request $request, SmsGatewayService $smsGateway): RedirectResponse
    {
        $data = $request->validate([
            'sms_test_phone' => ['required', 'string', 'max:32'],
            'sms_test_message' => ['required', 'string', 'max:480'],
        ]);

        $business = Business::firstOrCreate(['id' => 1], ['name' => 'Microfinance']);

        try {
            $result = $smsGateway->send(
                $business,
                (string) $data['sms_test_phone'],
                (string) $data['sms_test_message'],
            );
        } catch (RuntimeException $exception) {
            AuditService::record('sms.test.failed', $business, [], [
                'reason' => 'configuration_or_validation',
            ]);

            return back()
                ->withInput($request->only(['sms_test_phone', 'sms_test_message']))
                ->with('sms_test_error', $exception->getMessage());
        }

        AuditService::record($result['successful'] ? 'sms.test.sent' : 'sms.test.failed', $business, [], [
            'recipient' => $result['recipient'],
            'successful' => $result['successful'],
            'http_status' => $result['status'],
        ]);

        if ($result['successful']) {
            return back()->with(
                'sms_test_success',
                'Your test message was sent successfully to '.$result['recipient'].'. The SMS provider accepted it for delivery.',
            );
        }

        $status = $result['status'] !== null ? 'HTTP '.$result['status'].'. ' : '';
        $message = $status.$result['response'];

        return back()
            ->withInput($request->only(['sms_test_phone', 'sms_test_message']))
            ->with('sms_test_error', 'Test SMS failed. '.$message);
    }
}
