<?php

namespace App\Http\Controllers\Web;

use App\Http\Controllers\Controller;
use App\Models\CompanySetting;
use App\Models\UserProfileIntro;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Storage;
use Illuminate\Validation\Rules\Password;

class SettingsController extends Controller
{
    private function companyId(): ?int
    {
        return auth()->user()?->company_id;
    }

    private function getCompanySetting(string $key, $default = null)
    {
        if (! $this->companyId()) {
            return $default;
        }
        $s = CompanySetting::withoutGlobalScopes()->where('company_id', $this->companyId())->where('key', $key)->first();
        return $s ? $s->value : $default;
    }

    private function setCompanySetting(string $key, ?string $value): void
    {
        if (! $this->companyId()) {
            return;
        }
        CompanySetting::withoutGlobalScopes()->updateOrCreate(
            ['company_id' => $this->companyId(), 'key' => $key],
            ['value' => $value ?? '']
        );
    }

    public function index()
    {
        $settings = CompanySetting::orderBy('key')->get();
        $company = auth()->user()?->company;
        $sequence = null;
        if ($this->companyId()) {
            $sequence = DB::table('employee_number_sequences')
                ->where('company_id', $this->companyId())
                ->first();
        }
        $employeeNumberPrefix = strtoupper(trim((string) ($sequence->prefix ?? null)));
        $employeeNumberDigits = max(1, min(10, (int) ($sequence->digits ?? 1)));

        return view('settings.index', compact('settings', 'company', 'employeeNumberPrefix', 'employeeNumberDigits'));
    }

    public function companyUpdate(Request $request)
    {
        $company = auth()->user()?->company;
        if (! $company) {
            return redirect()->route('settings.index')->with('error', 'Company not found.');
        }
        abort_unless((int) $company->id === (int) auth()->user()->company_id, 403);

        $gstin = $request->input('gstin');
        if ($gstin !== null && trim((string) $gstin) !== '') {
            $request->merge(['gstin' => strtoupper(preg_replace('/\s+/', '', (string) $gstin))]);
        } else {
            $request->merge(['gstin' => null]);
        }

        $validated = $request->validate([
            'name' => 'required|string|max:255',
            'short_name' => 'nullable|string|max:100',
            'email' => 'nullable|email|max:255',
            'phone' => 'nullable|string|max:50',
            'website' => 'nullable|string|max:255',
            'address' => 'nullable|string|max:1000',
            'employee_number_prefix' => ['nullable', 'string', 'max:20', 'regex:/^[A-Za-z0-9_#-]+$/'],
            'employee_number_digits' => ['nullable', 'integer', 'min:1', 'max:10'],
            'gstin' => [
                'nullable',
                'string',
                'size:15',
                'regex:/^[0-9]{2}[A-Z]{5}[0-9]{4}[A-Z][1-9A-Z]Z[0-9A-Z]$/',
            ],
        ]);

        $employeeNumberPrefix = strtoupper(trim((string) ($validated['employee_number_prefix'] ?? null)));
        $employeeNumberDigits = (int) ($validated['employee_number_digits'] ?? 1);
        unset($validated['employee_number_prefix']);
        unset($validated['employee_number_digits']);

        $company->update($validated);
        $existingSequence = DB::table('employee_number_sequences')
            ->where('company_id', (int) $company->id)
            ->first();
        $normalizedPrefix = $employeeNumberPrefix !== '' ? $employeeNumberPrefix : null;
        $normalizedDigits = max(1, min(10, $employeeNumberDigits));

        if ($existingSequence) {
            DB::table('employee_number_sequences')
                ->where('company_id', (int) $company->id)
                ->update([
                    'prefix' => $normalizedPrefix,
                    'digits' => $normalizedDigits,
                    'updated_at' => now(),
                ]);
        } else {
            DB::table('employee_number_sequences')->insert([
                'company_id' => (int) $company->id,
                'prefix' => $normalizedPrefix,
                'digits' => $normalizedDigits,
                'last_number' => 0,
                'created_at' => now(),
                'updated_at' => now(),
            ]);
        }

        return redirect()->route('settings.index')->with('success', 'Company details updated successfully.');
    }

    public function home()
    {
        $user = auth()->user();
        $superAdmin = (bool) ($user?->is_superadmin ?? false);
        $can = fn (string $p) => $superAdmin || ($user && $user->hasPermission($p));

        $sidebarModules = config('tenant_modules.sidebar_module', []);
        $allowedMods = $allowedModules ?? null;
        $moduleAllowed = function (string $perm) use ($allowedMods, $sidebarModules) {
            if ($allowedMods === null) {
                return true;
            }
            $mod = $sidebarModules[$perm] ?? null;
            if ($mod === null) {
                return true;
            }
            return in_array($mod, $allowedMods, true);
        };
        $canShow = fn (string $p) => $can($p) && $moduleAllowed($p);

        $tiles = [
            ['title' => 'General', 'desc' => 'Company settings', 'icon' => 'bi-gear', 'route' => 'settings.index', 'perm' => 'manage_settings'],
            ['title' => 'Email', 'desc' => 'SMTP & mail settings', 'icon' => 'bi-envelope', 'route' => 'settings.email', 'perm' => 'manage_settings'],
            ['title' => 'Roles & permissions', 'desc' => 'System and custom roles', 'icon' => 'bi-shield-lock', 'route' => 'tenant-roles.index', 'perm' => 'roles_view'],

            ['title' => 'Departments', 'desc' => 'Org structure setup', 'icon' => 'bi-building', 'route' => 'departments.index', 'perm' => 'users_view'],
            ['title' => 'Designations', 'desc' => 'Job titles & roles', 'icon' => 'bi-award', 'route' => 'designations.index', 'perm' => 'users_view'],
            ['title' => 'Locations', 'desc' => 'Office locations', 'icon' => 'bi-geo-alt', 'route' => 'locations.index', 'perm' => 'users_view'],
            ['title' => 'Shifts', 'desc' => 'Working hours setup', 'icon' => 'bi-clock', 'route' => 'shifts.index', 'perm' => 'attendances_view'],
            ['title' => 'Weekoff Rules', 'desc' => 'Weekly off patterns', 'icon' => 'bi-calendar-week', 'route' => 'weekoff-rules.index', 'perm' => 'attendances_view'],

            ['title' => 'Leave Types', 'desc' => 'Leave policies', 'icon' => 'bi-tags', 'route' => 'leave-types.index', 'perm' => 'leaves_view'],
            ['title' => 'Holiday Calendar', 'desc' => 'Company holidays', 'icon' => 'bi-calendar-event', 'route' => 'holidays.index', 'perm' => 'leaves_view'],

            ['title' => 'Payroll Settings', 'desc' => 'PF/ESI/PT config', 'icon' => 'bi-gear-wide-connected', 'route' => 'payroll.index', 'params' => ['tab' => 'setup', 'sub' => 'pf_esi'], 'perm' => 'payrolls_view'],
            ['title' => 'Salary Groups', 'desc' => 'Salary structure', 'icon' => 'bi-people-fill', 'route' => 'salary-groups.index', 'perm' => 'payrolls_view'],
            ['title' => 'Salary Components', 'desc' => 'Earnings & deductions', 'icon' => 'bi-stack', 'route' => 'salary-components.index', 'perm' => 'payrolls_view'],

            ['title' => 'Asset Types', 'desc' => 'Asset category setup', 'icon' => 'bi-tags', 'route' => 'asset-types.index', 'perm' => 'assets_view'],

            ['title' => 'Payees', 'desc' => 'Payee master', 'icon' => 'bi-person-dash', 'route' => 'payees.index', 'perm' => 'finance_view'],
            ['title' => 'Payers', 'desc' => 'Payer master', 'icon' => 'bi-person-plus', 'route' => 'payers.index', 'perm' => 'finance_view'],
            ['title' => 'Deposit Categories', 'desc' => 'Deposit classification', 'icon' => 'bi-tags', 'route' => 'deposit-categories.index', 'perm' => 'finance_view'],
            ['title' => 'Vendors', 'desc' => 'Vendor directory', 'icon' => 'bi-shop', 'route' => 'vendors.index', 'perm' => 'finance_view'],

            ['title' => 'Letter Head Templates', 'desc' => 'Letterhead & print', 'icon' => 'bi-file-earmark-richtext', 'route' => 'letter-head-templates.index', 'perm' => 'documents_view'],
            ['title' => 'Forms', 'desc' => 'Form builder', 'icon' => 'bi-ui-checks', 'route' => 'forms.index', 'perm' => 'documents_view'],

            ['title' => 'Company Policies', 'desc' => 'Policy documents', 'icon' => 'bi-shield-check', 'route' => 'company-policies.index', 'perm' => 'hr_operations_view'],
            ['title' => 'Announcements', 'desc' => 'Company updates', 'icon' => 'bi-megaphone', 'route' => 'announcements.index', 'perm' => 'announcements_view'],
            ['title' => 'Reports', 'desc' => 'Analytics & exports', 'icon' => 'bi-bar-chart-line', 'route' => 'reports.index', 'perm' => 'view_reports'],
        ];

        $tiles = array_values(array_filter($tiles, fn ($t) => $canShow($t['perm'])));

        return view('settings.home', compact('tiles'));
    }

    public function store(Request $request)
    {
        $validated = $request->validate([
            'key' => 'required|string|max:100',
            'value' => 'nullable|string|max:2000',
        ]);
        CompanySetting::updateOrCreate(
            [
                'company_id' => auth()->user()->company_id,
                'key' => $validated['key'],
            ],
            ['value' => $validated['value'] ?? '']
        );
        return redirect()->route('settings.index')->with('success', 'Setting saved successfully.');
    }

    public function logoStore(Request $request)
    {
        $request->validate([
            'logo' => 'required|image|mimes:png,jpg,jpeg,webp|max:2048',
        ]);

        $company = auth()->user()?->company;
        if (! $company) {
            return redirect()->route('settings.index')->with('error', 'Company not found.');
        }

        $oldLogo = $company->logo;
        $logoPath = $request->file('logo')->store('company-logos', 'public');
        $company->logo = $logoPath;
        $company->save();

        if ($oldLogo && $oldLogo !== $logoPath && Storage::disk('public')->exists($oldLogo)) {
            Storage::disk('public')->delete($oldLogo);
        }

        return redirect()->route('settings.index')->with('success', 'Company logo updated successfully.');
    }

    public function logoDestroy()
    {
        $company = auth()->user()?->company;
        if (! $company) {
            return redirect()->route('settings.index')->with('error', 'Company not found.');
        }

        $oldLogo = $company->logo;
        $company->logo = null;
        $company->save();

        if ($oldLogo && Storage::disk('public')->exists($oldLogo)) {
            Storage::disk('public')->delete($oldLogo);
        }

        return redirect()->route('settings.index')->with('success', 'Company logo removed successfully.');
    }

    public function emailIndex()
    {
        $mail = [
            'mail_mailer' => $this->getCompanySetting('mail_mailer', config('mail.default', 'smtp')),
            'mail_from_name' => $this->getCompanySetting('mail_from_name', config('mail.from.name', config('app.name'))),
            'mail_from_address' => $this->getCompanySetting('mail_from_address', config('mail.from.address', '')),
            'mail_host' => $this->getCompanySetting('mail_host', config('mail.mailers.smtp.host', '')),
            'mail_port' => $this->getCompanySetting('mail_port', config('mail.mailers.smtp.port', '587')),
            'mail_encryption' => $this->getCompanySetting('mail_encryption', config('mail.mailers.smtp.encryption', 'tls')),
            'mail_username' => $this->getCompanySetting('mail_username', ''),
            'mail_password' => $this->getCompanySetting('mail_password', ''),
            'mail_queue' => $this->getCompanySetting('mail_queue', 'no'),
        ];
        $hasPassword = (bool) $this->getCompanySetting('mail_password');
        return view('settings.email', compact('mail', 'hasPassword'));
    }

    public function emailStore(Request $request)
    {
        $request->validate([
            'mail_mailer' => 'required|string|in:smtp,log',
            'mail_from_name' => 'required|string|max:255',
            'mail_from_address' => 'required|email',
            'mail_host' => 'nullable|string|max:255',
            'mail_port' => 'nullable|string|max:20',
            'mail_encryption' => 'nullable|string|in:tls,ssl,null',
            'mail_username' => 'nullable|string|max:255',
            'mail_password' => 'nullable|string|max:255',
            'mail_queue' => 'nullable|string|in:yes,no',
        ]);
        $this->setCompanySetting('mail_mailer', $request->mail_mailer);
        $this->setCompanySetting('mail_from_name', $request->mail_from_name);
        $this->setCompanySetting('mail_from_address', $request->mail_from_address);
        $this->setCompanySetting('mail_host', $request->mail_host ?? '');
        $this->setCompanySetting('mail_port', $request->mail_port ?? '587');
        $this->setCompanySetting('mail_encryption', $request->mail_encryption ?? 'tls');
        $this->setCompanySetting('mail_username', $request->mail_username ?? '');
        if ($request->filled('mail_password')) {
            $this->setCompanySetting('mail_password', $request->mail_password);
        }
        $this->setCompanySetting('mail_queue', $request->mail_queue ?? 'no');
        return redirect()->route('settings.email')->with('success', 'Email settings updated.');
    }

    public function emailTestMail(Request $request)
    {
        $request->validate(['to' => 'required|email']);
        $to = $request->to;
        $companyId = $this->companyId();
        try {
            if ($companyId) {
                \App\Services\TenantMailConfig::applyForCompany($companyId, function () use ($to) {
                    Mail::raw('This is a test email from your company HRMS. If you received this, your SMTP settings are working.', function ($message) use ($to) {
                        $message->to($to)->subject('Test email – ' . config('app.name'));
                    });
                });
            } else {
                Mail::raw('This is a test email from your company HRMS.', function ($message) use ($to) {
                    $message->to($to)->subject('Test email – ' . config('app.name'));
                });
            }
            return redirect()->route('settings.email')->with('success', 'Test email sent to ' . $to);
        } catch (\Throwable $e) {
            return redirect()->route('settings.email')->with('error', 'Failed to send test email: ' . $e->getMessage());
        }
    }

    public function profileIndex()
    {
        $user = auth()->user();
        $intro = UserProfileIntro::query()->firstOrCreate(['user_id' => $user->id]);
        $quickLinks = $this->normalizeQuickLinks($intro->quick_links);
        $profileCompletion = $this->profileCompletionPercent($user, $intro);

        return view('settings.profile', compact('user', 'intro', 'quickLinks', 'profileCompletion'));
    }

    public function profileUpdate(Request $request)
    {
        $user = auth()->user();
        $rules = [
            'name' => 'required|string|max:255',
            'email' => 'required|email|max:255|unique:users,email,' . $user->id,
            'profile_photo' => 'nullable|image|mimes:jpg,jpeg,png,webp|max:2048',
        ];
        if ($request->filled('password')) {
            $rules['password'] = ['required', 'confirmed', Password::defaults()];
        }
        $data = $request->validate($rules);
        $user->name = $data['name'];
        $user->email = $data['email'];
        if (! empty($data['password'] ?? null)) {
            $user->password = Hash::make($data['password']);
        }
        if ($request->hasFile('profile_photo')) {
            $oldPhoto = $user->profile_photo;
            $newPhotoPath = $request->file('profile_photo')->store('profile-photos', 'public');
            $user->profile_photo = $newPhotoPath;

            if (
                $oldPhoto &&
                ! str_starts_with($oldPhoto, 'http://') &&
                ! str_starts_with($oldPhoto, 'https://') &&
                $oldPhoto !== $newPhotoPath &&
                Storage::disk('public')->exists($oldPhoto)
            ) {
                Storage::disk('public')->delete($oldPhoto);
            }
        }
        $user->save();

        return redirect()->route('settings.profile')->with('success', 'Profile updated.');
    }

    public function updateSelfIntro(Request $request)
    {
        $user = auth()->user();

        $validated = $request->validate([
            'about' => ['nullable', 'string', 'max:2000'],
            'job_love' => ['nullable', 'string', 'max:2000'],
            'interests_hobbies' => ['nullable', 'string', 'max:2000'],
            'past_experience' => ['nullable', 'string', 'max:2000'],
            'quick_links' => ['nullable', 'array', 'max:6'],
            'quick_links.linkedin' => 'nullable|url|max:255',
            'quick_links.instagram' => 'nullable|url|max:255',
            'quick_links.facebook' => 'nullable|url|max:255',
        ]);

        UserProfileIntro::query()->updateOrCreate(
            ['user_id' => $user->id],
            [
                'about' => $validated['about'] ?? null,
                'job_love' => $validated['job_love'] ?? null,
                'interests_hobbies' => $validated['interests_hobbies'] ?? null,
                'past_experience' => $validated['past_experience'] ?? null,
                'quick_links' => [
                    'linkedin' => $this->normalizeQuickLinkValue(data_get($validated, 'quick_links.linkedin')),
                    'instagram' => $this->normalizeQuickLinkValue(data_get($validated, 'quick_links.instagram')),
                    'facebook' => $this->normalizeQuickLinkValue(data_get($validated, 'quick_links.facebook')),
                ],
            ]
        );

        return redirect()->route('settings.profile')->with('success', 'Profile updated.');
    }

    private function normalizeQuickLinks(mixed $quickLinks): array
    {
        $links = is_array($quickLinks) ? $quickLinks : [];

        // Backward compatibility: previous shape stored a numeric array.
        if (array_is_list($links)) {
            $links = [
                'linkedin' => $links[0] ?? null,
                'instagram' => $links[1] ?? null,
                'facebook' => $links[2] ?? null,
            ];
        }

        return [
            'linkedin' => $this->normalizeQuickLinkValue($links['linkedin'] ?? null),
            'instagram' => $this->normalizeQuickLinkValue($links['instagram'] ?? null),
            'facebook' => $this->normalizeQuickLinkValue($links['facebook'] ?? null),
        ];
    }

    private function normalizeQuickLinkValue(mixed $value): ?string
    {
        $trimmed = trim((string) ($value ?? ''));
        return $trimmed !== '' ? $trimmed : null;
    }

    private function profileCompletionPercent(User $user, ?UserProfileIntro $intro): int
    {
        $signals = [
            ! empty($user->profile_photo),
            ! empty($user->phone),
            ! empty($user->dob),
            ! empty($user->joining_date),
            ! empty($user->department_id),
            ! empty($user->designation_id),
            ! empty($intro?->about),
            ! empty($intro?->job_love),
            ! empty($intro?->interests_hobbies),
            ! empty($intro?->past_experience),
        ];

        $completed = count(array_filter($signals, fn (bool $value): bool => $value));
        $total = max(1, count($signals));

        return (int) round(($completed / $total) * 100);
    }
}
