<?php

namespace App\Http\Controllers;

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
{
    /**
     * Display a listing of the resource.
     */
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) {

                // Search in GrantDeptMap table
                $q->where('GDM_Id', 'like', "%{$search}%")

                // Search in Department table
                ->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_ledgers = $mapping->ledgers();
                return $mapping;
            });
        } else {
            $data = $query->paginate((int) $perPage);

            $data->getCollection()->transform(function ($mapping) {
                $mapping->all_ledgers = $mapping->ledgers();
                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' => $e->getMessage()
        ], 500);
    }
}



public function all()
{
    try {

        $mappings = GrantDeptMap::with(['department'])
            ->get()
            ->map(function ($mapping) {
                $mapping->all_ledgers = $mapping->ledgers();
                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' => $e->getMessage()
        ], 500);
    }
}

    /**
     * Store a newly created resource in storage.
     */
    public function store(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'Dept_Id'  => 'nullable|exists:dept_master,Dpt_id',
            'Lg_Id'   => 'required|array|min:1',
            'Lg_Id.*' => 'exists:ledger_master,Lg_Id',
        ]);

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

        try {
            $ledgerIds = array_unique($request->Lg_Id);

            $mapping = GrantDeptMap::create([
                'Dept_Id' => $request->Dept_Id,
                'Lg_Id'  => $ledgerIds,
            ]);

            $mapping->load(['department']);
            $mapping->all_ledgers = $mapping->ledgers();

            return response()->json([
                'success' => true,
                'data'    => $mapping,
                'message' => 'Grant department mapping created successfully.'
            ], 201);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Failed to create mapping.',
                'error'   => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Display the specified resource.
     */
    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_ledgers = $mapping->ledgers();

            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'   => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Update the specified resource in storage.
     */
    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',
                'Lg_Id'   => 'sometimes|array|min:1',
                'Lg_Id.*' => 'exists:ledger_master,Lg_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('Lg_Id')) {
                $updateData['Lg_Id'] = array_unique($request->Lg_Id);
            }

            if (!empty($updateData)) {
                $mapping->update($updateData);
            }

            $mapping->load(['department']);
            $mapping->all_ledgers = $mapping->ledgers();

            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'   => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Remove the specified resource from storage.
     */
    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'   => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Search mappings by department
     */
    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_ledgers = $mapping->ledgers();
                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'   => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Get mappings by department ID
     */
    public function byDepartment($deptId)
    {
        try {
            $mappings = GrantDeptMap::with(['department'])
                ->where('Dept_Id', $deptId)
                ->get()
                ->map(function ($mapping) {
                    $mapping->all_ledgers = $mapping->ledgers();
                    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'   => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Get mappings by ledger ID
     */
    public function byLedger($ledgId)
    {
        try {
            $mappings = GrantDeptMap::with(['department'])
                ->whereJsonContains('Lg_Id', $ledgId)
                ->get()
                ->map(function ($mapping) {
                    $mapping->all_ledgers = $mapping->ledgers();
                    return $mapping;
                });

            return response()->json([
                'success' => true,
                'data'    => $mappings,
                'message' => 'Mappings retrieved by ledger successfully.'
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Failed to retrieve mappings.',
                'error'   => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Get all departments for a specific ledger
     */
    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'   => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Get all ledgers for a specific department
     */
    public function ledgersForDepartment($deptId)
    {
        try {
            $mappings = GrantDeptMap::where('Dept_Id', $deptId)->get();

            $allLedgerIds = [];
            foreach ($mappings as $mapping) {
                if (!empty($mapping->Lg_Id)) {
                    $allLedgerIds = array_merge($allLedgerIds, $mapping->Lg_Id);
                }
            }

            $allLedgerIds = array_unique($allLedgerIds);
            $ledgers = LedgerMaster::whereIn('Lg_Id', $allLedgerIds)->get();

            return response()->json([
                'success' => true,
                'data'    => $ledgers,
                'total_unique_ledgers' => count($allLedgerIds),
                'message' => 'Ledgers for department retrieved successfully.'
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Failed to retrieve ledgers.',
                'error'   => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Add ledger IDs to an existing mapping
     */
    public function addLedgers(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(), [
                'Lg_Id'   => 'required|array|min:1',
                'Lg_Id.*' => 'exists:ledger_master,Lg_Id',
            ]);

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

            $currentLedgerIds = $mapping->Lg_Id ?? [];
            $newLedgerIds = array_unique($request->Lg_Id);
            $mergedLedgerIds = array_unique(array_merge($currentLedgerIds, $newLedgerIds));

            $mapping->Lg_Id = $mergedLedgerIds;
            $mapping->save();

            $mapping->load(['department']);
            $mapping->all_ledgers = $mapping->ledgers();

            return response()->json([
                'success' => true,
                'data' => $mapping,
                'added_count' => count(array_diff($newLedgerIds, $currentLedgerIds)),
                'total_ledgers' => count($mergedLedgerIds),
                'message' => 'Ledgers added successfully.'
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Failed to add ledgers.',
                'error'   => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Remove ledger IDs from an existing mapping
     */
    public function removeLedgers(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(), [
                'Lg_Id'   => 'required|array|min:1',
                'Lg_Id.*' => 'exists:ledger_master,Lg_Id',
            ]);

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

            $currentLedgerIds = $mapping->Lg_Id ?? [];
            $removeLedgerIds = $request->Lg_Id;
            $updatedLedgerIds = array_diff($currentLedgerIds, $removeLedgerIds);

            if (empty($updatedLedgerIds)) {
                $mapping->delete();
                return response()->json([
                    'success' => true,
                    'message' => 'All ledgers removed. Mapping deleted.',
                ]);
            }

            $mapping->Lg_Id = array_values($updatedLedgerIds);
            $mapping->save();

            $mapping->load(['department']);
            $mapping->all_ledgers = $mapping->ledgers();

            return response()->json([
                'success' => true,
                'data' => $mapping,
                'removed_count' => count(array_intersect($currentLedgerIds, $removeLedgerIds)),
                'remaining_ledgers' => count($updatedLedgerIds),
                'message' => 'Ledgers removed successfully.'
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Failed to remove ledgers.',
                'error'   => $e->getMessage()
            ], 500);
        }
    }
}
