<?php

namespace App\Http\Controllers;

use App\Models\CmChecklistItem;
use App\Models\CheckMeasure;
use App\Models\ScheduledReport;
use App\Models\User;
use App\Models\Role;
use App\Models\ActivityLog;
use App\Models\AppSetting;
use App\Models\RolePermission;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Storage;

class SettingsController extends Controller
{
    public function index()
    {
        $recentActivity   = ActivityLog::with('user')->latest()->take(20)->get();
        $settings         = AppSetting::all()->pluck('value', 'key');
        $scheduledReports = ScheduledReport::with('creator')->latest()->get();
        return view('settings.index', compact('recentActivity', 'settings', 'scheduledReports'));
    }

    public function update(Request $request)
    {
        $data = $request->validate([
            'company_name'             => 'nullable|string|max:255',
            'company_abn'              => 'nullable|string|max:20',
            'company_phone'            => 'nullable|string|max:30',
            'company_email'            => 'nullable|email',
            'company_address'          => 'nullable|string|max:255',
            'company_website'          => 'nullable|url',
            'licence_number'           => 'nullable|string|max:50',
            'default_job_stage'        => 'nullable|string|in:lead,consult,sold',
            'lead_expiry_days'         => 'nullable|integer|min:0',
            'followup_reminder_days'   => 'nullable|integer|min:1',
            'warranty_years'           => 'nullable|integer|min:0',
            'project_types'            => 'nullable|string|max:500',
            'lead_sources'             => 'nullable|string|max:500',
            'prefix_lead'              => 'nullable|string|max:5',
            'prefix_job'               => 'nullable|string|max:5',
            'prefix_quote'             => 'nullable|string|max:5',
            'default_markup'           => 'nullable|numeric|min:0|max:200',
            'default_gst'              => 'nullable|numeric|min:0|max:100',
            'quote_valid_days'         => 'nullable|integer|min:1',
            'currency_symbol'          => 'nullable|string|max:3',
            'deposit_pct'              => 'nullable|numeric|min:0|max:100',
            'cm_pct'                   => 'nullable|numeric|min:0|max:100',
            'delivery_pct'             => 'nullable|numeric|min:0|max:100',
            'completion_pct'           => 'nullable|numeric|min:0|max:100',
            'invoice_prefix'           => 'nullable|string|max:8',
            'payment_terms'            => 'nullable|string|in:deposit_on_acceptance,7_days,14_days,30_days',
            'invoice_overdue_days'     => 'nullable|integer|min:1',
            'bank_name'                => 'nullable|string|max:100',
            'bank_bsb'                 => 'nullable|string|max:10',
            'bank_account'             => 'nullable|string|max:20',
            'custom_fields_json'       => 'nullable|string',
            'quote_header'             => 'nullable|string',
            'quote_footer'             => 'nullable|string',
            'contract_intro'           => 'nullable|string',
            'completion_text'          => 'nullable|string',
            'quote_terms_days'         => 'nullable|integer|min:1',
            'notify_new_lead'          => 'nullable|in:true,false',
            'notify_stage_change'      => 'nullable|in:true,false',
            'notify_payment'           => 'nullable|in:true,false',
            'notify_quote_accepted'    => 'nullable|in:true,false',
            'notify_quote_expiry'      => 'nullable|in:true,false',
            'notify_cm_scheduled'      => 'nullable|in:true,false',
            'notify_install_scheduled' => 'nullable|in:true,false',
            'notify_warranty'          => 'nullable|in:true,false',
            'session_timeout'          => 'nullable|integer|min:5|max:1440',
            'password_min_length'      => 'nullable|integer|min:6',
            'security_require_upper'   => 'nullable|in:true,false',
            'security_require_numbers' => 'nullable|in:true,false',
            'security_multi_session'   => 'nullable|in:true,false',
            'security_log_views'       => 'nullable|in:true,false',
            'log_retention_days'       => 'nullable|integer|min:30',
            'trash_retention_days'     => 'nullable|integer|min:7',
            'smtp_host'                => 'nullable|string|max:255',
            'smtp_port'                => 'nullable|integer|min:1|max:65535',
            'smtp_username'            => 'nullable|string|max:255',
            'smtp_password'            => 'nullable|string|max:255',
            'smtp_encryption'          => 'nullable|in:tls,ssl,starttls,none',
            'smtp_from_address'        => 'nullable|email',
            'smtp_from_name'           => 'nullable|string|max:255',
            'cm_manufacture_lead_days' => 'nullable|integer|min:1|max:30',
            'cm_checklist_defaults'    => 'nullable|string',
        ]);

        if (isset($data['custom_fields_json'])) {
            $decoded = json_decode($data['custom_fields_json'], true);
            $data['custom_fields'] = is_array($decoded) ? json_encode($decoded) : null;
            unset($data['custom_fields_json']);
        }

        // ── Sync CM checklist template items on existing check measures ───────
        if (array_key_exists('cm_checklist_defaults', $data)) {
            $this->syncCmChecklistDefaults($data['cm_checklist_defaults'] ?? '');
        }

        $groupMap = [
            'company_name' => 'company', 'company_abn' => 'company', 'company_phone' => 'company',
            'company_email' => 'company', 'company_address' => 'company',
            'company_website' => 'company', 'licence_number' => 'company',
            'default_job_stage' => 'job_settings', 'lead_expiry_days' => 'job_settings',
            'followup_reminder_days' => 'job_settings', 'warranty_years' => 'job_settings',
            'project_types' => 'job_settings', 'lead_sources' => 'job_settings',
            'prefix_lead' => 'job_settings', 'prefix_job' => 'job_settings', 'prefix_quote' => 'job_settings',
            'default_markup' => 'financial', 'default_gst' => 'financial',
            'quote_valid_days' => 'financial', 'currency_symbol' => 'financial',
            'deposit_pct' => 'financial', 'cm_pct' => 'financial',
            'delivery_pct' => 'financial', 'completion_pct' => 'financial',
            'invoice_prefix' => 'financial', 'payment_terms' => 'financial',
            'invoice_overdue_days' => 'financial',
            'work_order_fault_threshold' => 'financial',
            'bank_name' => 'financial', 'bank_bsb' => 'financial', 'bank_account' => 'financial',
            'custom_fields' => 'custom_fields',
            'quote_header' => 'templates', 'quote_footer' => 'templates',
            'contract_intro' => 'templates', 'completion_text' => 'templates',
            'quote_terms_days' => 'templates',
            'notify_new_lead' => 'notifications', 'notify_stage_change' => 'notifications',
            'notify_payment' => 'notifications', 'notify_quote_accepted' => 'notifications',
            'notify_quote_expiry' => 'notifications', 'notify_cm_scheduled' => 'notifications',
            'notify_install_scheduled' => 'notifications', 'notify_warranty' => 'notifications',
            'session_timeout' => 'security', 'password_min_length' => 'security',
            'security_require_upper' => 'security', 'security_require_numbers' => 'security',
            'security_multi_session' => 'security', 'security_log_views' => 'security',
            'log_retention_days' => 'data_storage', 'trash_retention_days' => 'data_storage',
            'smtp_host' => 'smtp',
            'cm_manufacture_lead_days' => 'job_settings',
            'cm_checklist_defaults' => 'job_settings',
            'smtp_port' => 'smtp', 'smtp_username' => 'smtp',
            'smtp_password' => 'smtp', 'smtp_encryption' => 'smtp',
            'smtp_from_address' => 'smtp', 'smtp_from_name' => 'smtp',
        ];

        $saved = 0;
        foreach ($data as $key => $value) {
            if ($value !== null) {
                AppSetting::set($key, $value, $groupMap[$key] ?? 'general');
                $saved++;
            }
        }

        ActivityLog::create([
            'user_id'       => auth()->id(),
            'loggable_type' => 'Settings',
            'loggable_id'   => 0,
            'action'        => 'Settings Updated',
            'description'   => auth()->user()->name . " updated {$saved} setting(s)",
        ]);

        return redirect()->route('settings.index')->with('success', 'Settings saved successfully.');
    }

    /**
     * Sync CM checklist default items to all existing (non-completed) check measures.
     *
     * - Items that exist in the template but not on the check measure → added.
     * - Template items on the check measure that are no longer in the template → deleted
     *   (only if they haven't been checked yet — preserves audit trail of completed items).
     * - Template items whose text changed → updated in place.
     */
    private function syncCmChecklistDefaults(string $defaults): void
    {
        // Parse new template items (fix: double-quoted "\n" splits actual newlines)
        $newItems = array_values(array_filter(array_map('trim', explode("\n", $defaults))));

        // Only sync to non-completed check measures
        $checkMeasures = CheckMeasure::whereNotIn('status', ['completed', 'cancelled'])->get();

        foreach ($checkMeasures as $cm) {
            // Get current template items on this check measure
            $existingTemplates = CmChecklistItem::where('check_measure_id', $cm->id)
                ->where('is_template', true)
                ->orderBy('sort_order')
                ->get();

            $existingTexts = $existingTemplates->pluck('item')->toArray();

            // Remove template items that are no longer in the new template (only unchecked ones)
            foreach ($existingTemplates as $existing) {
                if (!in_array($existing->item, $newItems) && !$existing->checked) {
                    $existing->delete();
                }
            }

            // Add new template items that don't exist yet on this check measure
            $maxSort = CmChecklistItem::where('check_measure_id', $cm->id)->max('sort_order') ?? -1;
            foreach ($newItems as $idx => $itemText) {
                if (!in_array($itemText, $existingTexts)) {
                    CmChecklistItem::create([
                        'check_measure_id' => $cm->id,
                        'item'             => $itemText,
                        'sort_order'       => $maxSort + $idx + 1,
                        'is_template'      => true,
                    ]);
                }
            }
        }
    }

    public function uploadLogo(Request $request)
    {
        $request->validate(['logo' => 'required|image|mimes:png,jpg,jpeg,svg,gif|max:2048']);
        $path = $request->file('logo')->store('logos', 'public');
        AppSetting::set('company_logo', $path, 'company');
        ActivityLog::create([
            'user_id'       => auth()->id(),
            'loggable_type' => 'Settings',
            'loggable_id'   => 0,
            'action'        => 'Logo Uploaded',
            'description'   => auth()->user()->name . ' uploaded a new company logo',
        ]);
        return back()->with('success', 'Logo uploaded successfully.');
    }

    // ── User management ───────────────────────────────────────────────────────

    public function users()
    {
        $users = User::with('role')->orderBy('name')->get();
        $roles = Role::orderBy('display_name')->get();
        return view('settings.users', compact('users', 'roles'));
    }

    public function storeUser(Request $request)
    {
        $data = $request->validate([
            'name'          => 'required|string|max:255',
            'email'         => 'required|email|unique:users,email',
            'password'      => 'required|string|min:8',
            'role_id'       => 'nullable|exists:roles,id',
            'phone'         => 'nullable|string',
            'hourly_rate'   => 'nullable|numeric|min:0',
            'employee_type' => 'nullable|in:processor,employee,trades',
        ]);
        $data['password'] = Hash::make($data['password']);
        $data['is_active'] = true;
        User::create($data);
        return redirect()->route('settings.users')->with('success', 'User created.');
    }

    public function updateUser(Request $request, User $user)
    {
        $data = $request->validate([
            'name'          => 'required|string|max:255',
            'email'         => 'required|email|unique:users,email,' . $user->id,
            'role_id'       => 'nullable|exists:roles,id',
            'phone'         => 'nullable|string',
            'hourly_rate'   => 'nullable|numeric|min:0',
            'employee_type' => 'nullable|in:processor,employee,trades',
        ]);
        $user->update($data);
        return redirect()->route('settings.users')->with('success', 'User updated.');
    }

    public function permissions()
    {
        $roles = Role::orderBy('display_name')->get();
        $rolePermissions = [];
        foreach ($roles as $role) {
            $rolePermissions[$role->name] = RolePermission::forRole($role->id);
        }

        $permissionGroups = [
            'Leads' => [
                'leads.view'   => 'View Leads (sidebar + list)',
                'leads.create' => 'Create Leads',
                'leads.edit'   => 'Edit Leads',
                'leads.delete' => 'Delete Leads',
                'leads.convert'=> 'Convert Lead to Job',
            ],
            'Jobs' => [
                'jobs.view'         => 'View Jobs (sidebar + list)',
                'jobs.create'       => 'Create Jobs',
                'jobs.edit'         => 'Edit Jobs',
                'jobs.delete'       => 'Delete Jobs',
                'jobs.advance_stage'=> 'Advance Job Stage',
            ],
            'Contacts' => [
                'contacts.view'  => 'View Contacts (sidebar + list)',
                'contacts.create'=> 'Create Contacts',
                'contacts.edit'  => 'Edit Contacts',
                'contacts.delete'=> 'Delete Contacts',
            ],
            'Calendar' => [
                'calendar.view'  => 'View Calendar (sidebar + access)',
                'calendar.manage'=> 'Create / Edit / Delete Calendar Events',
            ],
            'Finance — Quotes' => [
                'quotes.view'   => 'View Quotes (sidebar + list)',
                'quotes.create' => 'Create Quotes',
                'quotes.edit'   => 'Edit Quotes',
                'quotes.delete' => 'Delete Quotes',
                'quotes.convert'=> 'Convert Quote to Contract',
            ],
            'Finance — Contracts' => [
                'contracts.view'  => 'View Contracts (sidebar + list)',
                'contracts.create'=> 'Create Contracts',
                'contracts.edit'  => 'Edit Contracts',
                'contracts.delete'=> 'Delete Contracts',
            ],
            'Finance — Materials' => [
                'materials.view'  => 'View Materials Catalogue (sidebar + list)',
                'materials.manage'=> 'Manage Materials Catalogue (add/edit/delete)',
            ],
            'Operations — Check Measure' => [
                'check_measure.view'  => 'View Check Measures (sidebar + list)',
                'check_measure.create'=> 'Create Check Measures',
                'check_measure.edit'  => 'Edit Check Measures',
            ],
            'Operations — Processing' => [
                'processing.view'  => 'View Processing (sidebar + list)',
                'processing.manage'=> 'Manage Processing Orders',
            ],
            'Operations — Delivery' => [
                'delivery.view'  => 'View Deliveries (sidebar + list)',
                'delivery.manage'=> 'Manage Deliveries (create/edit/deliver)',
            ],
            'Operations — Installation' => [
                'installation.view'  => 'View Installations (sidebar + list)',
                'installation.manage'=> 'Manage Installations (create/edit/complete)',
            ],
            'Operations — Completion' => [
                'completion.view'  => 'View Completions (sidebar + list)',
                'completion.manage'=> 'Manage Completions (create/edit)',
            ],
            'Procurement — Purchase Orders' => [
                'purchase_orders.view'   => 'View Purchase Orders (sidebar + list)',
                'purchase_orders.create' => 'Create Purchase Orders',
                'purchase_orders.edit'   => 'Edit Purchase Orders',
                'purchase_orders.delete' => 'Delete Purchase Orders',
                'purchase_orders.receive'=> 'Receive Stock against PO',
            ],
            'Procurement — Inventory' => [
                'inventory.view'  => 'View Inventory (sidebar + list)',
                'inventory.manage'=> 'Manage Inventory (adjust / allocate)',
            ],
            'Time & Pay — Timesheets' => [
                'timesheet.view' => 'View Own Timesheet (sidebar + access)',
                'timesheet.admin'=> 'View All Staff Timesheets (Staff Time page)',
            ],
            'Time & Pay — Staff Invoices' => [
                'staff_invoices.view'   => 'View Own Invoices (sidebar + access)',
                'staff_invoices.approve'=> 'Approve / Reject / Mark Paid Staff Invoices',
            ],
            'Reports' => [
                'reports.view' => 'View Reports (sidebar + all report pages)',
            ],
        ];

        return view('settings.permissions', compact('roles', 'rolePermissions', 'permissionGroups'));
    }

    public function updatePermissions(Request $request, Role $role)
    {
        $all = collect($request->input('permissions', []));
        $allPerms = collect([
            'leads.view','leads.create','leads.edit','leads.delete','leads.convert',
            'jobs.view','jobs.create','jobs.edit','jobs.delete','jobs.advance_stage',
            'contacts.view','contacts.create','contacts.edit','contacts.delete',
            'calendar.view','calendar.manage',
            'quotes.view','quotes.create','quotes.edit','quotes.delete','quotes.convert',
            'contracts.view','contracts.create','contracts.edit','contracts.delete',
            'materials.view','materials.manage',
            'check_measure.view','check_measure.create','check_measure.edit',
            'processing.view','processing.manage',
            'delivery.view','delivery.manage',
            'installation.view','installation.manage',
            'completion.view','completion.manage',
            'purchase_orders.view','purchase_orders.create','purchase_orders.edit','purchase_orders.delete','purchase_orders.receive',
            'inventory.view','inventory.manage',
            'timesheet.view','timesheet.admin',
            'staff_invoices.view','staff_invoices.approve',
            'reports.view',
        ]);
        foreach ($allPerms as $perm) {
            RolePermission::updateOrCreate(
                ['role_id' => $role->id, 'permission' => $perm],
                ['granted' => $all->contains($perm)]
            );
        }
        return back()->with("success", "Permissions saved for {$role->display_name}.");
    }

    public function toggleUser(User $user)
    {
        if ($user->id === auth()->id()) {
            return back()->with('error', 'You cannot deactivate your own account.');
        }
        $user->update(['is_active' => ! $user->is_active]);
        $status = $user->is_active ? 'activated' : 'deactivated';
        return back()->with('success', "User {$user->name} {$status}.");
    }

    public function changePassword(Request $request)
    {
        $request->validate([
            'current_password' => 'required|string',
            'new_password'     => 'required|string|min:8|confirmed',
        ]);
        if (! Hash::check($request->current_password, auth()->user()->password)) {
            return back()->with('error', 'Current password is incorrect.')->withInput();
        }
        auth()->user()->update(['password' => Hash::make($request->new_password)]);
        ActivityLog::create([
            'user_id'       => auth()->id(),
            'loggable_type' => 'User',
            'loggable_id'   => auth()->id(),
            'action'        => 'Password Changed',
            'description'   => auth()->user()->name . ' changed their password',
        ]);
        return back()->with('success', 'Password updated successfully.');
    }
}
