<?php

namespace App\Http\Controllers;

use App\Models\BudgetHead;
use App\Models\GrantDeptMap;
use App\Models\DeptMaster;
use App\Models\LedgerMaster;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;

class GrantDeptMapController extends Controller
{
   
    public function index(Request $request)
    {
        try {

            $perPage = $request->get('per_page', 25);
            $search = $request->get('search', '');
            $withTrashed = $request->get('with_trashed', false);

            $query = GrantDeptMap::with(['department'])
                ->orderBy('GDM_Id', 'desc');

            if ($withTrashed) {
                $query->withTrashed();
            }

            if ($search) {

                $query->where(function ($q) use ($search) {

                    $q->where('GDM_Id', 'like', "%{$search}%")

                        ->orWhereHas('department', function ($dept) use ($search) {
                            $dept->where('Dpt_Name', 'like', "%{$search}%")
                                ->orWhere('Dpt_Desc', 'like', "%{$search}%");
                        });
                });
            }

            if ($perPage === 'all') {

                $data = $query->get()->map(function ($mapping) {
                    $mapping->all_budget_heads = $mapping->budgetHeads();
                    return $mapping;
                });
            } else {

                $data = $query->paginate((int) $perPage);

                $data->getCollection()->transform(function ($mapping) {
                    $mapping->all_budget_heads = $mapping->budgetHeads();
                    return $mapping;
                });
            }

            return response()->json([
                'success' => true,
                'data' => $data,
                'message' => 'Grant department mappings retrieved successfully.'
            ]);
        } catch (\Exception $e) {

            return response()->json([
                'success' => false,
                'message' => 'Failed to retrieve mappings.',
                'error' => env('Development_Mode') == 'Prod' 
        ? 'Something went wrong. Please try again later.' 
        : $e->getMessage()
            ], 500);
        }
    }

    public function all()
    {
        try {

            $mappings = GrantDeptMap::with(['department', ])
                ->get()
                ->map(function ($mapping) {
                    $mapping->all_budget_heads = $mapping->budgetHeads();
                    return $mapping;
                });

            return response()->json([
                'success' => true,
                'data' => $mappings,
                'message' => 'Grant department mappings retrieved successfully.'
            ]);
        } catch (\Exception $e) {

            return response()->json([
                'success' => false,
                'message' => 'Failed to retrieve mappings.',
                'error' => env('Development_Mode') == 'Prod' 
        ? 'Something went wrong. Please try again later.' 
        : $e->getMessage()
            ], 500);
        }
    }

 
    public function store(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'Dept_Id' => 'nullable|exists:dept_master,Dpt_id',
            'Bh_Id' => 'required|array|min:1',
            'Bh_Id.*' => 'exists:budget_head,Bh_Id'
        ]);

        if ($validator->fails()) {
            return response()->json([
                'success' => false,
                'errors' => $validator->errors()
            ], 422);
        }

        $bhIds = array_unique($request->Bh_Id);

        $mapping = GrantDeptMap::create([
            'Dept_Id' => $request->Dept_Id,
            'GT_Id'   => $request->GT_Id, 

            'Bh_Id' => $bhIds
        ]);

        $mapping->load('department');
        $mapping->all_budget_heads = $mapping->budgetHeads();

        return response()->json([
            'success' => true,
            'data' => $mapping,
            'message' => 'Mapping created successfully'
        ]);
    }
    public function show($id)
    {
        try {

            $mapping = GrantDeptMap::with(['department', ])->find($id);

            if (!$mapping) {
                return response()->json([
                    'success' => false,
                    'message' => 'Mapping not found.'
                ], 404);
            }

            $mapping->all_budget_heads = $mapping->budgetHeads();

            return response()->json([
                'success' => true,
                'data' => $mapping,
                'message' => 'Mapping retrieved successfully.'
            ]);
        } catch (\Exception $e) {

            return response()->json([
                'success' => false,
                'message' => 'Failed to retrieve mapping.',
                'error' => env('Development_Mode') == 'Prod' 
        ? 'Something went wrong. Please try again later.' 
        : $e->getMessage()
            ], 500);
        }
    }

 
    public function update(Request $request, $id)
    {
        try {
            $mapping = GrantDeptMap::find($id);

            if (!$mapping) {
                return response()->json([
                    'success' => false,
                    'message' => 'Mapping not found.'
                ], 404);
            }
            $validator = Validator::make($request->all(), [
                'Dept_Id' => 'sometimes|exists:dept_master,Dpt_id',
                'Bh_Id' => 'sometimes|array|min:1',
                'Bh_Id.*' => 'exists:budget_head,Bh_Id',

            ]);

            if ($validator->fails()) {
                return response()->json([
                    'success' => false,
                    'errors'  => $validator->errors(),
                    'message' => 'Validation failed.'
                ], 422);
            }

            $updateData = [];

            if ($request->has('Dept_Id')) {
                $updateData['Dept_Id'] = $request->Dept_Id;
            }

            if ($request->has('Bh_Id')) {
                $updateData['Bh_Id'] = array_unique($request->Bh_Id);
            }
            if ($request->has('GT_Id')) {
                $updateData['GT_Id'] = $request->GT_Id;
            }
            if (!empty($updateData)) {
                $mapping->update($updateData);
            }

            $mapping->load(['department']);
            $mapping->all_budget_heads = $mapping->budgetHeads();

            return response()->json([
                'success' => true,
                'data'    => $mapping,
                'message' => 'Mapping updated successfully.'
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Failed to update mapping.',
                'error' => env('Development_Mode') == 'Prod' 
        ? 'Something went wrong. Please try again later.' 
        : $e->getMessage()
            ], 500);
        }
    }


    public function destroy($id)
    {
        try {
            $mapping = GrantDeptMap::find($id);

            if (!$mapping) {
                return response()->json([
                    'success' => false,
                    'message' => 'Mapping not found.'
                ], 404);
            }

            $mapping->delete();

            return response()->json([
                'success' => true,
                'message' => 'Mapping deleted successfully.'
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Failed to delete mapping.',
                'error' => env('Development_Mode') == 'Prod' 
        ? 'Something went wrong. Please try again later.' 
        : $e->getMessage()
            ], 500);
        }
    }


    public function search(Request $request)
    {
        try {


            $query = GrantDeptMap::with(['department']);


            if ($request->has('Dept_Id')) {
                $query->where('Dept_Id', $request->Dept_Id);
            }


            $results = $query->get()->map(function ($mapping) {
                $mapping->all_budget_heads = $mapping->budgetHeads();
                return $mapping;
            });


            return response()->json([
                'success' => true,
                'data'    => $results,
                'message' => 'Search completed successfully.'
            ]);
        } catch (\Exception $e) {


            return response()->json([
                'success' => false,
                'message' => 'Search failed.',
                'error' => env('Development_Mode') == 'Prod' 
        ? 'Something went wrong. Please try again later.' 
        : $e->getMessage()
            ], 500);
        }
    }




    public function byDepartment($deptId)
    {
        try {

            $mappings = GrantDeptMap::with(['department'])
                ->where('Dept_Id', $deptId)
                ->get()
                ->map(function ($mapping) {
                    $mapping->all_budget_heads = $mapping->budgetHeads();
                    return $mapping;
                });

            return response()->json([
                'success' => true,
                'data'    => $mappings,
                'message' => 'Mappings retrieved by department successfully.'
            ]);
        } catch (\Exception $e) {

            return response()->json([
                'success' => false,
                'message' => 'Failed to retrieve mappings.',
                'error' => env('Development_Mode') == 'Prod' 
        ? 'Something went wrong. Please try again later.' 
        : $e->getMessage()
            ], 500);
        }
    }

    public function byBudgetHead($bhId)
    {
        $mappings = GrantDeptMap::with('department')
            ->whereJsonContains('Bh_Id', $bhId)
            ->get()
            ->map(function ($mapping) {
                $mapping->all_budget_heads = $mapping->budgetHeads();
                return $mapping;
            });

        return response()->json([
            'success' => true,
            'data' => $mappings
        ]);
    }


    public function departmentsForLedger($ledgId)
    {
        try {
            $mappings = GrantDeptMap::with('department')
                ->whereJsonContains('Lg_Id', $ledgId)
                ->get();

            $departments = $mappings->pluck('department')->filter();

            return response()->json([
                'success' => true,
                'data'    => $departments,
                'total_mappings' => $mappings->count(),
                'message' => 'Departments for ledger retrieved successfully.'
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Failed to retrieve departments.',
                'error' => env('Development_Mode') == 'Prod' 
        ? 'Something went wrong. Please try again later.' 
        : $e->getMessage()
            ], 500);
        }
    }


    public function budgetHeadsForDepartment($deptId)
    {
        $mappings = GrantDeptMap::where('Dept_Id', $deptId)->get();

        $allBhIds = [];

        foreach ($mappings as $mapping) {
            if (!empty($mapping->Bh_Id)) {
                $allBhIds = array_merge($allBhIds, $mapping->Bh_Id);
            }
        }

        $allBhIds = array_unique($allBhIds);

        $budgetHeads = BudgetHead::whereIn('Bh_Id', $allBhIds)->get();

        return response()->json([
            'success' => true,
            'data' => $budgetHeads
        ]);
    }

 
    public function addBudgetHeads(Request $request, $id)
    {
        try {

            $mapping = GrantDeptMap::find($id);

            if (!$mapping) {
                return response()->json([
                    'success' => false,
                    'message' => 'Mapping not found.'
                ], 404);
            }

            $validator = Validator::make($request->all(), [
                'Bh_Id'   => 'required|array|min:1',
                'Bh_Id.*' => 'exists:budget_head,Bh_Id',
            ]);

            if ($validator->fails()) {
                return response()->json([
                    'success' => false,
                    'errors'  => $validator->errors(),
                    'message' => 'Validation failed.'
                ], 422);
            }

            $currentBhIds = $mapping->Bh_Id ?? [];
            $newBhIds = array_unique($request->Bh_Id);

            $mergedBhIds = array_unique(array_merge($currentBhIds, $newBhIds));

            $mapping->Bh_Id = $mergedBhIds;
            $mapping->save();

            $mapping->load(['department']);
            $mapping->all_budget_heads = $mapping->budgetHeads();

            return response()->json([
                'success' => true,
                'data' => $mapping,
                'added_count' => count(array_diff($newBhIds, $currentBhIds)),
                'total_budget_heads' => count($mergedBhIds),
                'message' => 'Budget heads added successfully.'
            ]);
        } catch (\Exception $e) {

            return response()->json([
                'success' => false,
                'message' => 'Failed to add budget heads.',
                'error' => env('Development_Mode') == 'Prod' 
        ? 'Something went wrong. Please try again later.' 
        : $e->getMessage()
            ], 500);
        }
    }

    public function removeBudgetHeads(Request $request, $id)
    {
        try {

            $mapping = GrantDeptMap::find($id);

            if (!$mapping) {
                return response()->json([
                    'success' => false,
                    'message' => 'Mapping not found.'
                ], 404);
            }

            $validator = Validator::make($request->all(), [
                'Bh_Id'   => 'required|array|min:1',
                'Bh_Id.*' => 'exists:budget_head,Bh_Id',
            ]);

            if ($validator->fails()) {
                return response()->json([
                    'success' => false,
                    'errors'  => $validator->errors(),
                    'message' => 'Validation failed.'
                ], 422);
            }

            $currentBhIds = $mapping->Bh_Id ?? [];
            $removeBhIds = $request->Bh_Id;

            $updatedBhIds = array_diff($currentBhIds, $removeBhIds);

            if (empty($updatedBhIds)) {

                $mapping->delete();

                return response()->json([
                    'success' => true,
                    'message' => 'All budget heads removed. Mapping deleted.',
                ]);
            }

            $mapping->Bh_Id = array_values($updatedBhIds);
            $mapping->save();

            $mapping->load(['department']);
            $mapping->all_budget_heads = $mapping->budgetHeads();

            return response()->json([
                'success' => true,
                'data' => $mapping,
                'removed_count' => count(array_intersect($currentBhIds, $removeBhIds)),
                'remaining_budget_heads' => count($updatedBhIds),
                'message' => 'Budget heads removed successfully.'
            ]);
        } catch (\Exception $e) {

            return response()->json([
                'success' => false,
                'message' => 'Failed to remove budget heads.',
                'error' => env('Development_Mode') == 'Prod' 
        ? 'Something went wrong. Please try again later.' 
        : $e->getMessage()
            ], 500);
        }
    }

    public function budgetHeadLedgers($bhId)
    {
        try {


            $ledgers = LedgerMaster::where('Bh_Id', $bhId)
                ->where('Lg_Status', 1)
                ->get();


            if ($ledgers->isEmpty()) {
                return response()->json([
                    'success' => true,
                    'data' => [],
                    'message' => 'No ledgers found for this budget head.'
                ]);
            }


            return response()->json([
                'success' => true,
                'data' => $ledgers,
                'message' => 'Budget head wise ledgers fetched successfully.'
            ]);
        } catch (\Exception $e) {


            return response()->json([
                'success' => false,
                'message' => 'Failed to fetch ledger data.',
                'error' => env('Development_Mode') == 'Prod' 
        ? 'Something went wrong. Please try again later.' 
        : $e->getMessage()
            ], 500);
        }
    }
}
