<?php

namespace App\Http\Controllers;

use App\Models\Project;
use App\Models\Task;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

class ProjectController extends Controller
{
    protected $projectImport;

    public function __construct(\App\Services\ProjectImportService $projectImport)
    {
        $this->projectImport = $projectImport;
    }

    public function index(Request $request)
    {
        $user = $request->user();
        $search = $request->input('search', '');
        $scope = $request->input('scope', '');
        
        // Base query with relationships
        $query = Project::with(['assignedTo', 'creator', 'tasks', 'investor']);

        // Check if performing a search
        $isSearch = !empty($search);
        
        // Check if global scope requested (e.g. from Dashboard Total Projects)
        $isGlobal = $scope === 'global';

        if ($isSearch) {
             // GLOBAL SEARCH: Bypass role-based "assigned to me" filters
             $query->where(function ($q) use ($search) {
                 $q->where('company_name', 'LIKE', "%{$search}%")
                   ->orWhere('contact_person', 'LIKE', "%{$search}%")
                   ->orWhere('purpose', 'LIKE', "%{$search}%") 
                   ->orWhereHas('assignedTo', function ($subQuery) use ($search) {
                       $subQuery->where('name', 'LIKE', "%{$search}%")
                                ->orWhere('email', 'LIKE', "%{$search}%");
                   })
                   ->orWhereHas('creator', function ($subQuery) use ($search) {
                       $subQuery->where('name', 'LIKE', "%{$search}%")
                                ->orWhere('email', 'LIKE', "%{$search}%");
                   })
                   ->orWhereHas('tasks', function ($subQuery) use ($search) {
                       $subQuery->where('title', 'LIKE', "%{$search}%");
                   });
             });
        } elseif ($isGlobal) {
             // GLOBAL LIST: Bypass role-based filters
             // Filters for status can still apply if passed
             if ($request->has('status')) {
                 $query->where('status', $request->status);
             }
        } else {
             // NORMAL LISTING: Strict Role-based filtering
             if ($user->isAdmin()) {
                 // Admin sees all projects
             } elseif ($user->isHead()) {
                 // Head sees projects:
                 // 1. Created by them or their team
                 // 2. Assigned to them or their team
                 $teamMemberIds = $user->members()->pluck('users.id')->toArray();
                 $teamMemberIds[] = $user->id; // Include Head
 
                 $query->where(function($q) use ($teamMemberIds) {
                     $q->whereIn('created_by', $teamMemberIds)
                       ->orWhereHas('assignedTo', function ($sq) use ($teamMemberIds) {
                           $sq->whereIn('users.id', $teamMemberIds);
                       });
                 });
             } elseif ($user->isTeamMember()) {
                 // Team Member sees projects:
                 // 1. Created by them
                 // 2. Assigned to them
                 $query->where(function($q) use ($user) {
                     $q->where('created_by', $user->id)
                       ->orWhereHas('assignedTo', function ($sq) use ($user) {
                           $sq->where('users.id', $user->id);
                       });
                 });
             }
        }

        // Apply ordering and pagination
        $projects = $query->latest()->paginate(20);

        // Filter fields logic for Restricted View
        // Applies to both Search and Global Scope list for unassigned items
        $projects->getCollection()->transform(function ($project) use ($user) {
            $hasAccess = $user->isAdmin() || 
                $project->created_by == $user->id;

            // Add fields for Global Search/List display
            $project->added_by = $project->creator->name ?? 'Unknown';

            if (!$hasAccess) {
                 // Mask sensitive info
                 $project->mobile = '********';
                 $project->notes = '********';
                 // Visible: company_name, contact_person, purpose, added_by
            }
            $project->can_view_details = $hasAccess;
            
            return $project;
        });

        return response()->json($projects);
    }

    public function store(Request $request)
    {
        $user = $request->user();

        if ($user->isTeamMember()) {
             // Team members CAN create projects now (implied by "team only assign...")
        }

        $validated = $request->validate([
            'company_name' => 'required|string|max:255',
            'contact_person' => 'required|string|max:255',
            'mobile' => 'required|string|max:15',
            'purpose' => 'nullable|string',
            'deadline' => 'nullable|date',
            'status' => 'required|in:ongoing,completed',

            'investor_lead_id' => 'nullable|exists:leads,id',
            'notes' => 'nullable|string',
            'user_ids' => 'nullable|array', // Assign to Heads (now optional)
            'user_ids.*' => 'exists:users,id',
        ]);

        // Validate assignments only if user_ids is provided and not empty
        if (!empty($validated['user_ids'])) {
            $assignedUsers = \App\Models\User::whereIn('id', $validated['user_ids'])->with('role')->get();
            
            foreach ($assignedUsers as $assignedUser) {
                // 1. Prevent assigning to Admins
                if ($assignedUser->isAdmin()) {
                    return response()->json(['message' => "Cannot assign projects to Admin users ({$assignedUser->name})"], 422);
                }

                // 2. Head can only assign to their team members
                if ($user->isHead()) {
                    // Check if assigned user is in head's team or is the head themselves
                    $isMyTeam = $assignedUser->head->contains($user->id) || $assignedUser->id === $user->id;
                    if (!$isMyTeam) {
                        return response()->json(['message' => "You can only assign projects to your team members ({$assignedUser->name})"], 403);
                    }
                }

                // 3. Team Member can assign to their Head or Peers (Same Head)
                if ($user->isTeamMember()) {
                    $myHead = $user->head()->first();
                    if (!$myHead) {
                         if ($assignedUser->id !== $user->id) {
                            return response()->json(['message' => "You don't have a Head assigned, so you cannot assign others."], 403);
                         }
                    } else {
                        $isHead = $assignedUser->id === $myHead->id;
                        $isPeer = $assignedUser->head->contains($myHead->id);
                        $isSelf = $assignedUser->id === $user->id;

                        if (!$isHead && !$isPeer && !$isSelf) {
                            return response()->json(['message' => "You can only assign projects to your Head or Team members ({$assignedUser->name})"], 403);
                        }
                    }
                }
            }
        }

        DB::beginTransaction();
        try {
            $project = Project::create([
                'company_name' => $validated['company_name'],
                'contact_person' => $validated['contact_person'],
                'mobile' => $validated['mobile'],
                'purpose' => $validated['purpose'] ?? null,
                'deadline' => $validated['deadline'] ?? null,
                'status' => $validated['status'] ?? 'ongoing',
                'notes' => $validated['notes'] ?? null,
                'investor_lead_id' => $validated['investor_lead_id'] ?? null,
                'created_by' => $user->id,
            ]);

            // Attach users only if user_ids is provided and not empty
            if (!empty($validated['user_ids'])) {
                $project->assignedTo()->attach($validated['user_ids']);
            }
            $project->load(['assignedTo', 'creator']);

            DB::commit();

            return response()->json([
                'message' => 'Project created successfully',
                'project' => $project,
            ], 201);
        } catch (\Exception $e) {
            DB::rollBack();
            return response()->json(['message' => 'Failed to create project: ' . $e->getMessage()], 500);
        }
    }

    public function show($id, Request $request)
    {
        $user = $request->user();
        $project = Project::with(['assignedTo', 'creator', 'tasks.assignee', 'investor'])->findOrFail($id);

        if ($user->isAdmin()) {
            // Admin sees all
            return response()->json($project);
        }

        // Check access
        if ($user->isTeamMember()) {
            // Team member can view if:
            // 1. They created it
            // 2. It's assigned to them
            // 3. It's assigned to their head
            $headId = $user->head()->first()->id ?? null;
            
            $canView = ($project->created_by === $user->id) ||
                       $project->assignedTo->contains($user->id) ||
                       ($headId && $project->assignedTo->contains($headId));

            if (!$canView) {
                return response()->json(['message' => 'Unauthorized'], 403);
            }
        } elseif ($user->isHead()) {
            // Head can view if:
            // 1. Created by them
            // 2. Assigned to them
            // 3. Created by their team member
            // 4. Assigned to their team member
            
            $isCreator = $project->created_by === $user->id;
            $isAssigned = $project->assignedTo->contains($user->id);
            
            $teamMemberIds = $user->members->pluck('id')->toArray();
            $isTeamCreator = in_array($project->created_by, $teamMemberIds);
            
            // Allow if assigned to ANY team member
            $isTeamAssigned = $project->assignedTo->whereIn('id', $teamMemberIds)->isNotEmpty();

            if (!$isCreator && !$isAssigned && !$isTeamCreator && !$isTeamAssigned) {
                return response()->json(['message' => 'Unauthorized'], 403);
            }
        }

        return response()->json($project);
    }

    public function update(Request $request, $id)
    {
        $project = Project::with(['assignedTo', 'creator'])->findOrFail($id);
        $user = $request->user();

        if ($user->isTeamMember()) {
             // Allow if creator or assigned or head assigned
             $headId = $user->head()->first()->id ?? null;
             
             $isAssigned = $project->assignedTo->contains($user->id);
             $isCreator = $project->created_by === $user->id;
             $isHeadAssigned = $headId && $project->assignedTo->contains($headId); 

             if (!$isAssigned && !$isCreator && !$isHeadAssigned) {
                  return response()->json(['message' => 'Unauthorized'], 403);
             }
        } elseif ($user->isHead()) {
             // Head Logic matches show()
             $isCreator = $project->created_by === $user->id;
             $isAssigned = $project->assignedTo->contains($user->id);
             
             $teamMemberIds = $user->members->pluck('id')->toArray();
             $isTeamCreator = in_array($project->created_by, $teamMemberIds);
             $isTeamAssigned = $project->assignedTo->whereIn('id', $teamMemberIds)->isNotEmpty();

             if (!$isCreator && !$isAssigned && !$isTeamCreator && !$isTeamAssigned) {
                 return response()->json(['message' => 'Unauthorized'], 403);
             }
        }

        $validated = $request->validate([
            'company_name' => 'sometimes|required|string|max:255',
            'contact_person' => 'sometimes|required|string|max:255',
            'mobile' => 'sometimes|required|string|max:15',
            'purpose' => 'nullable|string',
            'deadline' => 'nullable|date',
            'status' => 'sometimes|in:ongoing,completed',

            'investor_lead_id' => 'nullable|exists:leads,id',
            'notes' => 'nullable|string',
            'user_ids' => 'sometimes|array',
            'user_ids.*' => 'exists:users,id',
        ]);

        if (isset($validated['user_ids'])) {
            // Validate assignments
            $assignedUsers = \App\Models\User::whereIn('id', $validated['user_ids'])->with('role')->get();
            
            foreach ($assignedUsers as $assignedUser) {
                // 1. Prevent assigning to Admins
                if ($assignedUser->isAdmin()) {
                    return response()->json(['message' => "Cannot assign projects to Admin users ({$assignedUser->name})"], 422);
                }

                // 2. Head can only assign to their team members
                if ($user->isHead()) {
                    // Check if assigned user is in head's team or is the head themselves
                    $isMyTeam = $assignedUser->head->contains($user->id) || $assignedUser->id === $user->id;
                    if (!$isMyTeam) {
                        return response()->json(['message' => "You can only assign projects to your team members ({$assignedUser->name})"], 403);
                    }
                }

                // 3. Team Member can assign to their Head or Peers (Same Head)
                if ($user->isTeamMember()) {
                    $myHead = $user->head()->first();
                    if (!$myHead) {
                         if ($assignedUser->id !== $user->id) {
                            return response()->json(['message' => "You don't have a Head assigned, so you cannot assign others."], 403);
                         }
                    } else {
                        $isHead = $assignedUser->id === $myHead->id;
                        $isPeer = $assignedUser->head->contains($myHead->id);
                        $isSelf = $assignedUser->id === $user->id;

                        if (!$isHead && !$isPeer && !$isSelf) {
                            return response()->json(['message' => "You can only assign projects to your Head or Team members ({$assignedUser->name})"], 403);
                        }
                    }
                }
            }
        }

        DB::beginTransaction();
        try {
            $project->update($validated);

            if (isset($validated['user_ids'])) {
                $project->assignedTo()->sync($validated['user_ids']);
            }

            $project->load(['assignedTo', 'creator']);

            DB::commit();

            return response()->json([
                'message' => 'Project updated successfully',
                'project' => $project,
            ]);
        } catch (\Exception $e) {
            DB::rollBack();
            return response()->json(['message' => 'Failed to update project'], 500);
        }
    }

    public function destroy($id, Request $request)
    {
        $user = $request->user();

        if ($user->isTeamMember()) {
            return response()->json(['message' => 'Unauthorized'], 403);
        }

        $project = Project::findOrFail($id);
        $project->delete();

        return response()->json(['message' => 'Project deleted successfully']);
    }

    // Task management
    public function tasks($projectId)
    {
        $project = Project::findOrFail($projectId);
        $tasks = $project->tasks()->with('assignee')->get();

        return response()->json($tasks);
    }

    public function storeTask(Request $request, $projectId)
    {
        $project = Project::findOrFail($projectId);

        $validated = $request->validate([
            'title' => 'required|string|max:255',
            'description' => 'nullable|string',
            'assigned_to' => 'nullable|exists:users,id',
            'status' => 'required|in:pending,in-progress,completed',
            'due_date' => 'nullable|date',
        ]);

        // Validate assignment if provided
        if (!empty($validated['assigned_to'])) {
            $assignedUser = \App\Models\User::find($validated['assigned_to']);
            $user = $request->user();

             // 1. Prevent assigning to Admins (if desired, assuming yes)
             if ($assignedUser->isAdmin()) {
                 return response()->json(['message' => "Cannot assign tasks to Admin users"], 422);
             }

             // 2. Head validation
             if ($user->isHead()) {
                 $isMyTeam = $assignedUser->head->contains($user->id) || $assignedUser->id === $user->id;
                 if (!$isMyTeam) {
                     return response()->json(['message' => "You can only assign tasks to your team members"], 403);
                 }
             }

             // 3. Team Member validation
             if ($user->isTeamMember()) {
                $myHead = $user->head()->first();
                if (!$myHead) {
                     if ($assignedUser->id !== $user->id) {
                        return response()->json(['message' => "You don't have a Head assigned."], 403);
                     }
                } else {
                    $isHead = $assignedUser->id === $myHead->id;
                    $isPeer = $assignedUser->head->contains($myHead->id);
                    $isSelf = $assignedUser->id === $user->id;

                    if (!$isHead && !$isPeer && !$isSelf) {
                        return response()->json(['message' => "You can only assign tasks to your Head or Team members"], 403);
                    }
                }
             }
        }

        $task = $project->tasks()->create($validated);
        $task->load('assignee');

        return response()->json([
            'message' => 'Task created successfully',
            'task' => $task,
        ], 201);
    }

    public function updateTask(Request $request, $projectId, $taskId)
    {
        $task = Task::where('project_id', $projectId)->findOrFail($taskId);

        $validated = $request->validate([
            'title' => 'sometimes|required|string|max:255',
            'description' => 'nullable|string',
            'assigned_to' => 'nullable|exists:users,id',
            'status' => 'sometimes|in:pending,in-progress,completed',
            'due_date' => 'nullable|date',
        ]);

        // Validate assignment if provided
        if (!empty($validated['assigned_to'])) {
            $assignedUser = \App\Models\User::find($validated['assigned_to']);
            $user = $request->user();

             if ($assignedUser->isAdmin()) {
                 return response()->json(['message' => "Cannot assign tasks to Admin users"], 422);
             }

             if ($user->isHead()) {
                 $isMyTeam = $assignedUser->head->contains($user->id) || $assignedUser->id === $user->id;
                 if (!$isMyTeam) {
                     return response()->json(['message' => "You can only assign tasks to your team members"], 403);
                 }
             }

             if ($user->isTeamMember()) {
                $myHead = $user->head()->first();
                if (!$myHead) {
                     if ($assignedUser->id !== $user->id) {
                        return response()->json(['message' => "You don't have a Head assigned."], 403);
                     }
                } else {
                    $isHead = $assignedUser->id === $myHead->id;
                    $isPeer = $assignedUser->head->contains($myHead->id);
                    $isSelf = $assignedUser->id === $user->id;

                    if (!$isHead && !$isPeer && !$isSelf) {
                        return response()->json(['message' => "You can only assign tasks to your Head or Team members"], 403);
                    }
                }
             }
        }

        $task->update($validated);
        $task->load('assignee');

        return response()->json([
            'message' => 'Task updated successfully',
            'task' => $task,
        ]);
    }

    public function deleteTask($projectId, $taskId)
    {
        $task = Task::where('project_id', $projectId)->findOrFail($taskId);
        $task->delete();

        return response()->json(['message' => 'Task deleted successfully']);
    }

    public function import(Request $request)
    {
        $user = $request->user();

        if ($user->isTeamMember()) {
            return response()->json(['message' => 'Unauthorized. Only Admin and Head can import projects.'], 403);
        }

        $request->validate([
            'file' => 'required|file|mimetypes:text/csv,text/plain,application/csv,text/comma-separated-values,application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/octet-stream',
            'user_ids' => 'nullable|array',
            'user_ids.*' => 'exists:users,id',
        ]);

        // Validate assignments only if provided
        if ($request->has('user_ids') && !empty($request->user_ids)) {
            $assignedUsers = \App\Models\User::whereIn('id', $request->user_ids)->with('role')->get();
            
            foreach ($assignedUsers as $assignedUser) {
                // 1. Prevent assigning to Admins
                if ($assignedUser->isAdmin()) {
                    return response()->json(['message' => "Cannot assign projects to Admin users ({$assignedUser->name})"], 422);
                }

                // 2. Head can only assign to their team members
                if ($user->isHead()) {
                    $isMyTeam = $assignedUser->head->contains($user->id) || $assignedUser->id === $user->id;
                    if (!$isMyTeam) {
                        return response()->json(['message' => "You can only assign projects to your team members ({$assignedUser->name})"], 403);
                    }
                }
            }
        }

        $file = $request->file('file');
        $filePath = $file->getRealPath();

        $result = $this->projectImport->importFromExcel(
            $filePath,
            $request->user_ids ?? [],
            $user->id
        );

        return response()->json([
            'message' => "Import completed. {$result['imported']} projects imported.",
            'imported' => $result['imported'],
            'errors' => $result['errors'],
        ]);
    }
}
