<?php

namespace App\Http\Controllers;

use App\Models\Generate_salary;
use App\Models\Generate_salary_detail;
use App\Models\Job_position;
use App\Models\Staff_member;
use App\Models\Staff_salary_struct;
use App\Models\Transaction;
use App\Models\Transaction_detail;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Barryvdh\DomPDF\Facade\Pdf;

class GenSalaryController extends Controller
{
    public function indexReport(Request $request)
    {
        $staffList = Staff_member::select('head_code', 'full_name', 'registration_no')->get();
        $query = Generate_salary_detail::with(['staff_member', 'generate_salary'])
            ->orderBy('id', 'desc');


        if ($request->filled('search')) {
            $query->where(function ($q) use ($request) {
                $q->where('reg_no', 'like', '%' . $request->search . '%')
                    ->orWhere('head_code', 'like', '%' . $request->search . '%');
            });
        }

        $staffs = $query->paginate($request->get('entries', 40)); // default to 10

        if ($request->ajax()) {
            return view('salary.partialGenReport', compact('staffs'))->render();
        }

        return view('salary.genSalaryReport', compact('staffs', 'staffList'));
    }

    public function index(Request $request)
    {
        $roles = Job_position::select('id', 'title')->get();
        $staffs = Staff_member::where('status', 'active')->get();

        // Check if the request is an AJAX request
        if ($request->ajax()) {
            $search = $request->input('search');

            // Fetch the filtered staff list or all staff if "All Staff" is selected
            $staffList = Staff_member::with('salaryStruct')
                ->when($search && $search !== 'all', function ($query) use ($search) {
                    $query->where('head_code', $search)
                        ->orWhere('full_name', 'like', "%{$search}%");
                })->where('status', 'active')
                ->orderBy('updated_at', 'desc')
                ->paginate(10); // Paginate results

            // Return the partial view with the filtered data
            return view('salary.partialSalaryList', compact('staffList'))->render();
        }

        // Default page load with all staff members
        $staffList = Staff_member::with('salaryStruct')
            ->where('status', 'active')
            ->orderBy('updated_at', 'desc')
            ->paginate(10);

        return view('salary.salaryList', compact('staffList', 'staffs', 'roles'));
    }

    public function pdfSalaryList(Request $request)
    {
        $staffList = Staff_member::with('salaryStruct')
            ->orderBy('updated_at', 'desc')
            ->get();

        $pdf = PDF::loadView('salary.pdfSalaryList', compact('staffList'));

        return $pdf->download('salary_list.pdf');
    }

    public function pdfSalaryGenerateReport(Request $request)
    {
        $month = $request->input('month');
        $year = $request->input('year');

        $query = Generate_salary_detail::with(['staff_member', 'generate_salary'])
            ->orderBy('id', 'desc');

        if ($month && $month !== 'all') {
            $query->whereHas('generate_salary', function ($q) use ($month) {
                $q->where('month', strtolower($month)); // match lowercase
            });
        }

        if ($year && $year !== 'all') {
            $query->whereHas('generate_salary', function ($q) use ($year) {
                $q->where('year', $year);
            });
        }

        $staffs = $query->get();

        $pdf = Pdf::loadView('salary.pdfSalaryGenReport', compact('staffs', 'month', 'year'));
        return $pdf->download("salary_report_{$month}_{$year}.pdf");
    }



    public function getSingle($head_code)
    {
        $staff = Staff_member::where('head_code', $head_code)->first();
        $s_St = Staff_salary_struct::where('head_code', $head_code)->first();

        return response()->json([
            'cnic_gn'   => $staff->cnic ?? '',
            'reg_no_gn' => $staff->registration_no ?? '',
            'salary_gn' =>  $staff->salary ?? 0,
            'b1_gn'     => $s_St->b1 ?? 0,
            'b2_gn'     => $s_St->b2 ?? 0,
            'b3_gn'     => $s_St->b3 ?? 0,
            'b4_gn'     => $s_St->b4 ?? 0,
            'b5_gn'     => $s_St->b5 ?? 0,
        ]);
    }

    public function salaryStore(Request $request)
    {
        $salaryType = $request->input('salaryType');

        if ($salaryType === 'single') {
            $v = $request->validate([
                'head_code_gn' => 'nullable|string',
                'cnic_gn' => 'nullable|string',
                'reg_no_gn' => 'nullable|string',
                'month_gn' => 'required|string',
                'salary_gn' => 'nullable|numeric',
                'b1_gn' => 'nullable|numeric',
                'b2_gn' => 'nullable|numeric',
                'b3_gn' => 'nullable|numeric',
                'b4_gn' => 'nullable|numeric',
                'b5_gn' => 'nullable|numeric',
                'date_gn' => 'required|date',
            ]);

            $getMonthIds = Generate_salary::where('month', $request->month_gn)
                ->where('year', (string)Carbon::parse($request->date_gn)->year)
                ->pluck('id'); // this is a collection of IDs

            $staffSalaryCheck = Generate_salary_detail::whereIn('gen_salary_id', $getMonthIds)
                ->where('head_code', $request->head_code_gn)
                ->first();

            if ($staffSalaryCheck) {
                return redirect()->route('staff.gen.indexR')->with('error', 'Salary already generated for this month.');
            }



            try {
                DB::beginTransaction();

                $t_amount =
                    (int) $request->salary_gn +
                    (int) $request->b1_gn +
                    (int) $request->b2_gn +
                    (int) $request->b3_gn +
                    (int) $request->b4_gn +
                    (int) $request->b5_gn;

                $gnId = Generate_salary::create([
                    'date' => $request->date_gn,
                    'month' => $request->month_gn,
                    'year' => Carbon::parse($request->date_gn)->year,
                    'total_amount' => $t_amount,
                ])->id;

                $hc = $request->head_code_gn;
                $staff = Staff_member::select('id')->where('head_code', $hc)->first();

                if (!$staff) {
                    throw new \Exception('Staff not found for given head code.');
                }

                Generate_salary_detail::create([
                    'gen_salary_id' => $gnId,
                    'staff_id' => $staff->id,
                    'head_code' => $hc,
                    'reg_no' => $request->reg_no_gn,
                    'salary' => $request->salary_gn,
                    'b1' => $request->b1_gn,
                    'b2' => $request->b2_gn,
                    'b3' => $request->b3_gn,
                    'b4' => $request->b4_gn,
                    'b5' => $request->b5_gn,
                ]);

                $tId = Transaction::create([
                    'transaction_type' => 'Generate Salary',
                    'trans_type_id' => $gnId,
                    'transaction_date' => $request->date_gn,
                    'total_amount'     => $t_amount,
                    'remarks'          => 'Generate Salary',
                ]);

                // Credit Salary on staff through head code
                Transaction_detail::create([
                    'transaction_id'   => $tId->id,
                    'coa_id'           => $hc,  // head code for staff
                    'transaction_type' => 'Generate Salary',
                    'debit'           => 0,
                    'credit'            => $t_amount,
                ]);

                // Debit Salary Expense through head code
                // Head code for salary expense 20300
                Transaction_detail::create([
                    'transaction_id'   => $tId->id,
                    'coa_id'           => '20300',  // head code for salary expense
                    'transaction_type' => 'Generate Salary',
                    'debit'           => $t_amount,
                    'credit'            => 0,
                ]);

                // Credit Amount from payable account
                // payable head code 20900
                Transaction_detail::create([
                    'transaction_id'   => $tId->id,
                    'coa_id'           => '20300',  // head code for payable
                    'transaction_type' => 'Generate Salary',
                    'debit'           => 0,
                    'credit'            => $t_amount,
                ]);


                DB::commit();
                return redirect()->route('staff.gen.indexR')->with('success', 'Salary generated successfully!');

                // return response()->json(['success' => true, 'message' => 'Salary generated successfully.']);
            } catch (\Exception $e) {
                DB::rollBack();

                return redirect()->route('staff.gen.indexR')->with('error', $e->getMessage());
            }
        } elseif ($salaryType === 'all') {
            $v = $request->validate([
                'month_gn' => 'required|string',
                'date_gn' => 'required|date',
            ]);

            DB::beginTransaction();

            try {
                $year = Carbon::parse($request->date_gn)->year;
                $month = $request->month_gn;

                // Get all salary records for this month/year
                $getMonthIds = Generate_salary::where('month', $month)
                    ->where('year', $year)
                    ->pluck('id');

                // Initialize arrays to track processing
                $skippedStaff = [];
                $staffToProcess = [];
                $processedHeadCodes = [];

                $staffList = Staff_member::where('status', 'active')->get();

                foreach ($staffList as $staff) {
                    // Check if this staff already has salary for this month/year
                    if ($getMonthIds->isNotEmpty()) {
                        $existingSalary = Generate_salary_detail::whereIn('gen_salary_id', $getMonthIds)
                            ->where('head_code', $staff->head_code)
                            ->exists();

                        if ($existingSalary) {
                            $skippedStaff[] = [
                                'id' => $staff->id,
                                'name' => $staff->full_name,
                                'reg_no' => $staff->registration_no,
                                'head_code' => $staff->head_code
                            ];
                            continue;
                        }
                    }

                    $staffToProcess[] = $staff;
                    $processedHeadCodes[] = $staff->head_code;
                }

                // If all staff are skipped, throw an error
                if (empty($staffToProcess)) {
                    throw new \Exception("All staff members already have salaries generated for {$month} {$year}!");
                }

                // Sum all salary fields for staff to process
                $t_salary = Staff_salary_struct::whereIn('head_code', $processedHeadCodes)
                    ->select(
                        DB::raw('SUM(salary) as t_salary'),
                        DB::raw('SUM(b1) as t_b1'),
                        DB::raw('SUM(b2) as t_b2'),
                        DB::raw('SUM(b3) as t_b3'),
                        DB::raw('SUM(b4) as t_b4'),
                        DB::raw('SUM(b5) as t_b5')
                    )->first();

                // Calculate total salary
                $All_Salary =
                    ($t_salary->t_salary ?? 0) +
                    ($t_salary->t_b1 ?? 0) +
                    ($t_salary->t_b2 ?? 0) +
                    ($t_salary->t_b3 ?? 0) +
                    ($t_salary->t_b4 ?? 0) +
                    ($t_salary->t_b5 ?? 0);

                // Create master salary generation record
                $gnId = Generate_salary::create([
                    'date' => $request->date_gn,
                    'month' => $month,
                    'year' => $year,
                    'total_amount' => $All_Salary,
                ])->id;

                $transaction = Transaction::create([
                    'transaction_type' => 'Generate Salary',
                    'trans_type_id' => $gnId,
                    'transaction_date' => $request->date_gn,
                    'total_amount' => $All_Salary,
                    'remarks' => 'Generate Salary',
                ]);

                foreach ($staffToProcess as $staff) {
                    $salaryData = Staff_salary_struct::where('head_code', $staff->head_code)->first();

                    if ($salaryData) {
                        Generate_salary_detail::create([
                            'gen_salary_id' => $gnId,
                            'staff_id' => $staff->id,
                            'head_code' => $staff->head_code,
                            'reg_no' => $staff->registration_no,
                            'salary' => $salaryData->salary,
                            'b1' => $salaryData->b1,
                            'b2' => $salaryData->b2,
                            'b3' => $salaryData->b3,
                            'b4' => $salaryData->b4,
                            'b5' => $salaryData->b5,
                        ]);

                        Transaction_detail::create([
                            'transaction_id' => $transaction->id,
                            'coa_id' => $staff->head_code,
                            'transaction_type' => 'Generate Salary',
                            'credit' => 0,
                            'debit' => $salaryData->salary + $salaryData->b1 + $salaryData->b2 + $salaryData->b3 + $salaryData->b4 + $salaryData->b5,
                        ]);
                    }
                }

                // Debit Salary Expense (20300)
                Transaction_detail::create([
                    'transaction_id' => $transaction->id,
                    'coa_id' => '20300',
                    'transaction_type' => 'Generate Salary',
                    'credit' => 0,
                    'debit' => $All_Salary,
                ]);

                // Credit from Payable head code 20900
                Transaction_detail::create([
                    'transaction_id' => $transaction->id,
                    'coa_id' => '20900',
                    'transaction_type' => 'Generate Salary',
                    'credit' => $All_Salary,
                    'debit' => 0,
                ]);

                DB::commit();

                // Prepare success message
                $successMessage = 'Total Salary ' .  $All_Salary . ' generated successfully for ' . count($staffToProcess) . ' staff members.';

                if (!empty($skippedStaff)) {
                    $skippedCount = count($skippedStaff);
                    $successMessage .= " {$skippedCount} staff members were skipped as they already have salaries.";

                    // Store skipped staff in session for display
                    session()->flash('skipped_staff', $skippedStaff);
                }

                return redirect()->route('staff.gen.indexR')->with('success', $successMessage);
            } catch (\Exception $e) {
                DB::rollBack();
                return redirect()->route('staff.gen.indexR')->with('error', $e->getMessage());
            }
        }
    }
}
