<?php

namespace App\Http\Controllers;

use App\Models\StaffInvoice;
use App\Models\TimeEntry;
use App\Models\User;
use App\Models\Job;
use App\Models\ActivityLog;
use Illuminate\Http\Request;
use Carbon\Carbon;

class StaffInvoiceController extends Controller
{
    public function index()
    {
        $user = auth()->user();
        $isAdminOrAccounts = in_array($user->role?->name, ['office_admin', 'accounts']);

        if ($isAdminOrAccounts) {
            $invoices = StaffInvoice::with('user.role', 'approver', 'job')
                ->orderByDesc('created_at')
                ->paginate(30);
        } else {
            $invoices = StaffInvoice::where('user_id', $user->id)
                ->with('approver', 'job')
                ->orderByDesc('created_at')
                ->paginate(30);
        }

        $pendingCount = $isAdminOrAccounts
            ? StaffInvoice::where('status', 'pending')->count()
            : 0;

        return view('staff-invoices.index', compact('invoices', 'pendingCount', 'isAdminOrAccounts'));
    }

    public function show(StaffInvoice $staffInvoice)
    {
        $user = auth()->user();
        $isAdminOrAccounts = in_array($user->role?->name, ['office_admin', 'accounts']);

        if (!$isAdminOrAccounts && $staffInvoice->user_id !== $user->id) {
            abort(403);
        }

        $staffInvoice->load('user.role', 'approver', 'timeEntries.taskType', 'timeEntries.job', 'job');
        return view('staff-invoices.show', compact('staffInvoice'));
    }

    public function generate(Request $request)
    {
        $data = $request->validate([
            'user_id'      => 'required|exists:users,id',
            'period_start' => 'nullable|date',
            'period_end'   => 'nullable|date|after_or_equal:period_start',
            'job_id'       => 'nullable|exists:crm_jobs,id',
        ]);

        // Require period dates when no specific job is chosen
        if (empty($data['job_id'])) {
            $request->validate([
                'period_start' => 'required|date',
                'period_end'   => 'required|date',
            ]);
        }

        $targetUser = User::findOrFail($data['user_id']);

        $entriesQuery = TimeEntry::where('user_id', $targetUser->id)
            ->where('status', 'completed')
            ->whereNull('invoiced_in');

        if (!empty($data['job_id'])) {
            // Job-specific invoice (primarily for trades)
            $entriesQuery->where('job_id', $data['job_id']);
        } else {
            // Period-based invoice
            $start = Carbon::parse($data['period_start'])->startOfDay();
            $end   = Carbon::parse($data['period_end'])->endOfDay();
            $entriesQuery->whereBetween('started_at', [$start, $end]);
        }

        $entries = $entriesQuery->get();

        if ($entries->isEmpty()) {
            return back()->with('error', 'No completed, uninvoiced time entries found for the selected criteria.');
        }

        $totalMinutes = $entries->sum('duration_minutes');
        $totalHours   = round($totalMinutes / 60, 2);
        $rate         = $targetUser->hourly_rate ?? 0;
        $totalAmount  = round($totalHours * $rate, 2);

        // Determine period from entries when job-specific (no explicit date range)
        if (!empty($data['job_id'])) {
            $periodStart = $entries->min('started_at') ? Carbon::parse($entries->min('started_at'))->toDateString() : now()->toDateString();
            $periodEnd   = $entries->max('started_at') ? Carbon::parse($entries->max('started_at'))->toDateString() : now()->toDateString();
        } else {
            $periodStart = $data['period_start'];
            $periodEnd   = $data['period_end'];
        }

        // Generate invoice number
        $count = StaffInvoice::count() + 1;
        $number = 'SI-' . str_pad($count, 5, '0', STR_PAD_LEFT);

        $invoice = StaffInvoice::create([
            'invoice_number' => $number,
            'user_id'        => $targetUser->id,
            'job_id'         => $data['job_id'] ?? null,
            'period_start'   => $periodStart,
            'period_end'     => $periodEnd,
            'total_hours'    => $totalHours,
            'hourly_rate'    => $rate,
            'total_amount'   => $totalAmount,
            'status'         => 'pending',
        ]);

        // Link time entries
        $entries->each(fn($e) => $e->update(['invoiced_in' => $invoice->id]));

        $jobLabel = !empty($data['job_id']) ? ' for job ' . (Job::find($data['job_id'])?->job_number ?? '') : '';

        ActivityLog::create([
            'user_id'       => auth()->id(),
            'loggable_type' => 'StaffInvoice',
            'loggable_id'   => $invoice->id,
            'action'        => 'Invoice Generated',
            'description'   => "Invoice {$number} generated for {$targetUser->name}{$jobLabel} — {$totalHours}h @ \${$rate}/h = \${$totalAmount}",
        ]);

        return redirect()->route('staff-invoices.show', $invoice)->with('success', "Invoice {$number} generated successfully.");
    }

    public function approve(Request $request, StaffInvoice $staffInvoice)
    {
        $data = $request->validate(['notes' => 'nullable|string|max:1000']);

        $staffInvoice->update([
            'status'         => 'approved',
            'approved_by'    => auth()->id(),
            'approved_at'    => now(),
            'approval_notes' => $data['notes'] ?? null,
        ]);

        ActivityLog::create([
            'user_id'       => auth()->id(),
            'loggable_type' => 'StaffInvoice',
            'loggable_id'   => $staffInvoice->id,
            'action'        => 'Invoice Approved',
            'description'   => auth()->user()->name . " approved invoice {$staffInvoice->invoice_number}" . ($staffInvoice->job ? ' (Job: ' . $staffInvoice->job->job_number . ')' : ''),
        ]);

        return back()->with('success', "Invoice {$staffInvoice->invoice_number} approved.");
    }

    public function reject(Request $request, StaffInvoice $staffInvoice)
    {
        $data = $request->validate(['notes' => 'required|string|max:1000']);

        // Release time entries
        $staffInvoice->timeEntries()->update(['invoiced_in' => null]);

        $staffInvoice->update([
            'status'         => 'rejected',
            'approved_by'    => auth()->id(),
            'approved_at'    => now(),
            'approval_notes' => $data['notes'],
        ]);

        ActivityLog::create([
            'user_id'       => auth()->id(),
            'loggable_type' => 'StaffInvoice',
            'loggable_id'   => $staffInvoice->id,
            'action'        => 'Invoice Rejected',
            'description'   => auth()->user()->name . " rejected invoice {$staffInvoice->invoice_number}: {$data['notes']}",
        ]);

        return back()->with('success', "Invoice rejected. Time entries released for re-invoicing.");
    }

    public function markPaid(StaffInvoice $staffInvoice)
    {
        $staffInvoice->update(['status' => 'paid']);
        return back()->with('success', "Invoice marked as paid.");
    }

    /**
     * Staff member requests invoice approval (period-based) — notifies all admin & accounts users.
     */
    public function requestApproval(Request $request)
    {
        $user = auth()->user();

        $data = $request->validate([
            'period_start' => 'required|date',
            'period_end'   => 'required|date|after_or_equal:period_start',
            'notes'        => 'nullable|string|max:500',
        ]);

        $start = \Carbon\Carbon::parse($data['period_start'])->startOfDay();
        $end   = \Carbon\Carbon::parse($data['period_end'])->endOfDay();

        // Count uninvoiced entries so staff knows if there's anything to invoice
        $uninvoicedCount = \App\Models\TimeEntry::where('user_id', $user->id)
            ->where('status', 'completed')
            ->whereNull('invoiced_in')
            ->whereBetween('started_at', [$start, $end])
            ->count();

        if ($uninvoicedCount === 0) {
            return back()->with('error', 'No completed, uninvoiced time entries found for this period.');
        }

        // Notify all admin and accounts users
        $adminIds = \App\Models\User::whereHas('role', fn($q) =>
            $q->whereIn('name', ['office_admin', 'accounts'])
        )->where('is_active', true)->pluck('id')->toArray();

        $period = $start->format('d M') . ' – ' . $end->format('d M Y');

        \App\Models\CrmNotification::broadcast([
            'type'    => 'invoice_request',
            'title'   => 'Invoice Approval Requested',
            'message' => "{$user->name} has requested invoice approval for {$period} ({$uninvoicedCount} entries)." . ($data['notes'] ? " Note: {$data['notes']}" : ''),
            'link'    => '/staff-invoices',
            'icon'    => 'fa-file-invoice-dollar',
        ], $adminIds);

        ActivityLog::create([
            'user_id'       => $user->id,
            'loggable_type' => 'StaffInvoice',
            'loggable_id'   => 0,
            'action'        => 'Invoice Approval Requested',
            'description'   => "{$user->name} requested invoice approval for {$period} ({$uninvoicedCount} entries)",
        ]);

        return back()->with('success', "Invoice approval request sent to admin & accounts for {$period}.");
    }

    /**
     * Trades person requests job-specific invoice approval.
     * Notifies all admin & accounts users with the specific job reference.
     */
    public function requestTradeJobApproval(Request $request)
    {
        $user = auth()->user();

        if ($user->role?->name !== 'trades') {
            abort(403);
        }

        $data = $request->validate([
            'job_id' => 'required|exists:crm_jobs,id',
            'notes'  => 'nullable|string|max:500',
        ]);

        $job = Job::findOrFail($data['job_id']);

        // Count uninvoiced completed entries for this job
        $uninvoicedCount = TimeEntry::where('user_id', $user->id)
            ->where('job_id', $data['job_id'])
            ->where('status', 'completed')
            ->whereNull('invoiced_in')
            ->count();

        if ($uninvoicedCount === 0) {
            return back()->with('error', 'No completed, uninvoiced time entries found for job ' . $job->job_number . '. Please complete the job first.');
        }

        // Calculate total hours for the notification
        $totalMins = TimeEntry::where('user_id', $user->id)
            ->where('job_id', $data['job_id'])
            ->where('status', 'completed')
            ->whereNull('invoiced_in')
            ->sum('duration_minutes');
        $totalHours = round($totalMins / 60, 2);
        $amount     = round($totalHours * ($user->hourly_rate ?? 0), 2);

        // Notify all admin and accounts users
        $adminIds = \App\Models\User::whereHas('role', fn($q) =>
            $q->whereIn('name', ['office_admin', 'accounts'])
        )->where('is_active', true)->pluck('id')->toArray();

        // \App\Models\CrmNotification::broadcast([
        //     'type'    => 'invoice_request',
        //     'title'   => 'Trade Invoice Approval Requested',
        //     'message' => "{$user->name} has requested invoice approval for job {$job->job_number} — {$totalHours}h @ \${$user->hourly_rate}/hr = \${$amount}." . ($data['notes'] ? " Note: {$data['notes']}" : ''),
        //     'link'    => '/staff-invoices',
        //     'icon'    => 'fa-file-invoice-dollar',
        // ], $adminIds);

        ActivityLog::create([
            'user_id'       => $user->id,
            'loggable_type' => 'StaffInvoice',
            'loggable_id'   => 0,
            'action'        => 'Trade Job Invoice Approval Requested',
            'description'   => "{$user->name} requested invoice approval for job {$job->job_number} ({$uninvoicedCount} entries, {$totalHours}h, \${$amount})",
        ]);

        return back()->with('success', "Invoice approval request sent to admin for job {$job->job_number}. ({$totalHours}h · \${$amount})");
    }
}
