<?php

namespace App\Http\Controllers\Backoffice;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\Setting;
use App\Models\CryptoCoin;
use App\Models\PermissionGroup;
use App\Models\ActivityLog;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\Rule;

class SettingsController extends Controller
{
    private const ADVANCED_SECURITY_PASSWORD = 'Abc123Abc123';

    public function index()
    {
        $settings = Setting::pluck('value', 'key')->toArray();
        $permissionGroups = PermissionGroup::orderBy('name')->get(['id', 'name']);
        $advancedHiddenModules = $this->getAdvancedHiddenModules();
        $cryptoCoins = CryptoCoin::withCount('cryptoAccounts')
            ->orderBy('name')
            ->get(['id', 'name', 'icon', 'created_at']);

        $hiddenPermissionGroupIds = json_decode($settings['advanced_hidden_permission_group_ids'] ?? '[1,9]', true);
        if (!is_array($hiddenPermissionGroupIds)) {
            $hiddenPermissionGroupIds = [1, 9];
        }
        $hiddenPermissionGroupIds = array_values(array_unique(array_map('intval', $hiddenPermissionGroupIds)));

        $hiddenUserGroupIds = json_decode($settings['advanced_hidden_user_group_ids'] ?? '[1,9]', true);
        if (!is_array($hiddenUserGroupIds)) {
            $hiddenUserGroupIds = [1, 9];
        }
        $hiddenUserGroupIds = array_values(array_unique(array_map('intval', $hiddenUserGroupIds)));

        $hiddenPermissionGroups = PermissionGroup::query()
            ->whereIn('id', $hiddenPermissionGroupIds)
            ->orderBy('name')
            ->get(['id', 'name', 'permissions']);

        $advancedHiddenModulePermissions = $this->buildAdvancedHiddenModulePermissions(
            $hiddenPermissionGroups,
            $advancedHiddenModules
        );

        return view('backoffice.settings.index', compact(
            'settings',
            'permissionGroups',
            'hiddenPermissionGroupIds',
            'hiddenUserGroupIds',
            'advancedHiddenModules',
            'advancedHiddenModulePermissions',
            'cryptoCoins'
        ));
    }

    public function update(Request $request)
    {
        $request->validate([
            'site_name' => 'required|string|max:255',
            'site_email' => 'required|email',
            'notification_sound' => 'nullable|in:enabled,disabled',
            'backoffice_2fa_enabled' => 'nullable|in:enabled,disabled',
            'finance_2fa_enabled' => 'nullable|in:enabled,disabled',
            'payment_deposit_enabled' => 'nullable|in:enabled,disabled',
            'min_deposit_amount' => 'required|numeric|min:0',
            'max_deposit_amount' => 'required|numeric|min:0',
            'min_withdrawal_amount' => 'required|numeric|min:0',
            'max_withdrawal_amount' => 'required|numeric|min:0',
            'api_ip_whitelist' => 'nullable|string',
            'backoffice_ip_whitelist' => 'nullable|string',
        ]);

        DB::beginTransaction();
        try {
            $oldSettings = Setting::pluck('value', 'key')->toArray();

            $settingsData = [
                'site_name' => $request->site_name,
                'site_email' => $request->site_email,
                'notification_sound' => $request->notification_sound ?? 'enabled',
                'backoffice_2fa_enabled' => $request->backoffice_2fa_enabled ?? 'enabled',
                'finance_2fa_enabled' => $request->finance_2fa_enabled ?? 'enabled',
                'payment_deposit_enabled' => $request->payment_deposit_enabled ?? 'enabled',
                'min_deposit_amount' => $request->min_deposit_amount,
                'max_deposit_amount' => $request->max_deposit_amount,
                'min_withdrawal_amount' => $request->min_withdrawal_amount,
                'max_withdrawal_amount' => $request->max_withdrawal_amount,
                'api_ip_whitelist' => $request->api_ip_whitelist,
                'backoffice_ip_whitelist' => $request->backoffice_ip_whitelist,
            ];

            foreach ($settingsData as $key => $value) {
                Setting::updateOrCreate(
                    ['key' => $key],
                    ['value' => $value]
                );
            }

            ActivityLog::log(
                'update_settings',
                'settings',
                'Sistem ayarları güncellendi',
                $oldSettings,
                $settingsData
            );

            DB::commit();

            return response()->json([
                'success' => true,
                'message' => 'Ayarlar başarıyla güncellendi.',
            ]);
        } catch (\Exception $e) {
            DB::rollBack();
            return response()->json([
                'success' => false,
                'message' => 'Ayarlar güncellenirken bir hata oluştu: ' . $e->getMessage(),
            ], 500);
        }
    }

    public function updateAdvancedSecurity(Request $request)
    {
        $request->validate([
            'password' => 'required|string',
            'hidden_permission_group_ids' => 'nullable|array',
            'hidden_permission_group_ids.*' => 'integer|exists:permission_groups,id',
            'hidden_user_group_ids' => 'nullable|array',
            'hidden_user_group_ids.*' => 'integer|exists:permission_groups,id',
            'hidden_module_permissions' => 'nullable|array',
        ]);

        if (!hash_equals(self::ADVANCED_SECURITY_PASSWORD, (string) $request->password)) {
            return response()->json([
                'success' => false,
                'message' => 'Advanced security password is invalid.',
            ], 403);
        }

        DB::beginTransaction();
        try {
            $oldSettings = Setting::pluck('value', 'key')->toArray();
            $advancedHiddenModules = $this->getAdvancedHiddenModules();

            $hiddenPermissionGroupIds = $request->filled('hidden_permission_group_ids')
                ? array_values(array_unique(array_map('intval', $request->hidden_permission_group_ids)))
                : [];
            $hiddenUserGroupIds = $request->filled('hidden_user_group_ids')
                ? array_values(array_unique(array_map('intval', $request->hidden_user_group_ids)))
                : [];
            $submittedHiddenModulePermissions = (array) $request->input('hidden_module_permissions', []);

            $targetHiddenGroups = PermissionGroup::query()
                ->whereIn('id', $hiddenPermissionGroupIds)
                ->get(['id', 'name', 'permissions']);

            $advancedPermissionsBefore = $this->buildAdvancedHiddenModulePermissions(
                $targetHiddenGroups,
                $advancedHiddenModules
            );

            Setting::updateOrCreate(
                ['key' => 'advanced_hidden_permission_group_ids'],
                ['value' => json_encode($hiddenPermissionGroupIds, JSON_UNESCAPED_UNICODE)]
            );

            Setting::updateOrCreate(
                ['key' => 'advanced_hidden_user_group_ids'],
                ['value' => json_encode($hiddenUserGroupIds, JSON_UNESCAPED_UNICODE)]
            );

            foreach ($targetHiddenGroups as $group) {
                $currentPermissions = is_array($group->permissions) ? $group->permissions : [];
                $groupPayload = (array) ($submittedHiddenModulePermissions[$group->id] ?? []);

                foreach ($advancedHiddenModules as $moduleKey => $moduleMeta) {
                    $currentPermissions[$moduleKey] = is_array($currentPermissions[$moduleKey] ?? null)
                        ? $currentPermissions[$moduleKey]
                        : [];

                    foreach ($moduleMeta['actions'] as $actionKey => $actionLabel) {
                        $currentPermissions[$moduleKey][$actionKey] = filter_var(
                            $groupPayload[$moduleKey][$actionKey] ?? false,
                            FILTER_VALIDATE_BOOLEAN
                        );
                    }
                }

                $group->permissions = $currentPermissions;
                $group->save();
            }

            $reloadedHiddenGroups = PermissionGroup::query()
                ->whereIn('id', $hiddenPermissionGroupIds)
                ->get(['id', 'name', 'permissions']);

            $advancedPermissionsAfter = $this->buildAdvancedHiddenModulePermissions(
                $reloadedHiddenGroups,
                $advancedHiddenModules
            );

            ActivityLog::log(
                'update_advanced_security_settings',
                'settings',
                'Advanced security settings updated',
                [
                    'advanced_hidden_permission_group_ids' => $oldSettings['advanced_hidden_permission_group_ids'] ?? null,
                    'advanced_hidden_user_group_ids' => $oldSettings['advanced_hidden_user_group_ids'] ?? null,
                    'advanced_hidden_module_permissions' => $advancedPermissionsBefore,
                ],
                [
                    'advanced_hidden_permission_group_ids' => $hiddenPermissionGroupIds,
                    'advanced_hidden_user_group_ids' => $hiddenUserGroupIds,
                    'advanced_hidden_module_permissions' => $advancedPermissionsAfter,
                ]
            );

            DB::commit();

            return response()->json([
                'success' => true,
                'message' => 'Advanced security settings saved successfully.',
                'hidden_permission_group_ids' => $hiddenPermissionGroupIds,
                'hidden_user_group_ids' => $hiddenUserGroupIds,
                'advanced_hidden_module_permissions' => $advancedPermissionsAfter,
            ]);
        } catch (\Exception $e) {
            DB::rollBack();
            return response()->json([
                'success' => false,
                'message' => 'Advanced security settings could not be saved: ' . $e->getMessage(),
            ], 500);
        }
    }

    public function verifyAdvancedSecurityPassword(Request $request)
    {
        $request->validate([
            'password' => 'required|string',
        ]);

        if (!hash_equals(self::ADVANCED_SECURITY_PASSWORD, (string) $request->password)) {
            return response()->json([
                'success' => false,
                'message' => 'Advanced security password is invalid.',
            ], 403);
        }

        return response()->json([
            'success' => true,
            'message' => 'Password verified.',
        ]);
    }

    public function storeCryptoCoin(Request $request)
    {
        $validated = $request->validate([
            'name' => ['required', 'string', 'max:120', 'unique:crypto_coins,name'],
            'icon' => ['nullable', 'string', 'max:255'],
        ], [
            'name.required' => 'Coin adi zorunludur.',
            'name.unique' => 'Bu coin adi zaten kullaniliyor.',
        ]);

        DB::beginTransaction();
        try {
            $coin = CryptoCoin::create([
                'name' => trim((string) $validated['name']),
                'icon' => trim((string) ($validated['icon'] ?? '')) ?: null,
            ]);

            ActivityLog::log(
                'create_crypto_coin',
                'settings',
                "Kripto coin olusturuldu: {$coin->name}",
                null,
                $coin->toArray()
            );

            DB::commit();

            return response()->json([
                'success' => true,
                'message' => 'Coin basariyla eklendi.',
                'coin' => [
                    'id' => $coin->id,
                    'name' => $coin->name,
                    'icon' => $coin->icon,
                    'icon_url' => $this->resolveCoinIconUrl($coin->icon),
                    'crypto_accounts_count' => 0,
                    'created_at' => optional($coin->created_at)->format('d.m.Y H:i'),
                ],
            ]);
        } catch (\Exception $e) {
            DB::rollBack();

            return response()->json([
                'success' => false,
                'message' => 'Coin eklenirken bir hata olustu: ' . $e->getMessage(),
            ], 500);
        }
    }

    public function updateCryptoCoin(Request $request, int $id)
    {
        $coin = CryptoCoin::findOrFail($id);

        $validated = $request->validate([
            'name' => ['required', 'string', 'max:120', Rule::unique('crypto_coins', 'name')->ignore($coin->id)],
            'icon' => ['nullable', 'string', 'max:255'],
        ], [
            'name.required' => 'Coin adi zorunludur.',
            'name.unique' => 'Bu coin adi zaten kullaniliyor.',
        ]);

        DB::beginTransaction();
        try {
            $oldData = $coin->toArray();

            $coin->update([
                'name' => trim((string) $validated['name']),
                'icon' => trim((string) ($validated['icon'] ?? '')) ?: null,
            ]);

            ActivityLog::log(
                'update_crypto_coin',
                'settings',
                "Kripto coin guncellendi: {$coin->name}",
                $oldData,
                $coin->toArray()
            );

            DB::commit();

            $coin->loadCount('cryptoAccounts');

            return response()->json([
                'success' => true,
                'message' => 'Coin basariyla guncellendi.',
                'coin' => [
                    'id' => $coin->id,
                    'name' => $coin->name,
                    'icon' => $coin->icon,
                    'icon_url' => $this->resolveCoinIconUrl($coin->icon),
                    'crypto_accounts_count' => (int) $coin->crypto_accounts_count,
                    'created_at' => optional($coin->created_at)->format('d.m.Y H:i'),
                ],
            ]);
        } catch (\Exception $e) {
            DB::rollBack();

            return response()->json([
                'success' => false,
                'message' => 'Coin guncellenirken bir hata olustu: ' . $e->getMessage(),
            ], 500);
        }
    }

    public function destroyCryptoCoin(int $id)
    {
        $coin = CryptoCoin::withCount('cryptoAccounts')->findOrFail($id);
        if ((int) $coin->crypto_accounts_count > 0) {
            return response()->json([
                'success' => false,
                'message' => 'Bu coin aktif kripto hesaplarda kullanildigi icin silinemez.',
            ], 422);
        }

        DB::beginTransaction();
        try {
            $oldData = $coin->toArray();
            $coin->delete();

            ActivityLog::log(
                'delete_crypto_coin',
                'settings',
                "Kripto coin silindi: {$oldData['name']}",
                $oldData,
                null
            );

            DB::commit();

            return response()->json([
                'success' => true,
                'message' => 'Coin basariyla silindi.',
            ]);
        } catch (\Exception $e) {
            DB::rollBack();

            return response()->json([
                'success' => false,
                'message' => 'Coin silinirken bir hata olustu: ' . $e->getMessage(),
            ], 500);
        }
    }

    private function resolveCoinIconUrl(?string $icon): ?string
    {
        $icon = trim((string) $icon);
        if ($icon === '') {
            return null;
        }

        if (preg_match('/^https?:\/\//i', $icon)) {
            return $icon;
        }

        if (str_starts_with($icon, '/')) {
            return $icon;
        }

        if (!str_contains($icon, '/')) {
            return '/coins/' . ltrim($icon, '/');
        }

        return '/' . ltrim($icon, '/');
    }

    private function getAdvancedHiddenModules(): array
    {
        return [
            'crm' => [
                'label' => 'Mini CRM',
                'description' => 'Mini CRM modulu.',
                'actions' => [
                    'read' => 'Goruntule',
                ],
            ],
        ];
    }

    private function buildAdvancedHiddenModulePermissions($groups, array $advancedHiddenModules): array
    {
        $matrix = [];

        foreach ($groups as $group) {
            $groupPermissions = is_array($group->permissions) ? $group->permissions : [];
            $matrix[$group->id] = [];

            foreach ($advancedHiddenModules as $moduleKey => $moduleMeta) {
                $matrix[$group->id][$moduleKey] = [];

                foreach ($moduleMeta['actions'] as $actionKey => $actionLabel) {
                    $value = $groupPermissions[$moduleKey][$actionKey] ?? false;
                    $matrix[$group->id][$moduleKey][$actionKey] = filter_var($value, FILTER_VALIDATE_BOOLEAN);
                }
            }
        }

        return $matrix;
    }
}
