<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Http\Requests\StoreBacklogItemRequest;
use App\Http\Resources\BacklogItemResource;
use App\Http\Resources\TaskResource;
use App\Models\BacklogItem;
use App\Models\Project;
use App\Models\Task;
use App\Services\ActivityLogService;
use App\Services\NotificationService;
use App\Services\ResourceAccessService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\Rule;
use Illuminate\Validation\ValidationException;

class BacklogController extends Controller
{
    public function __construct(
        private readonly ResourceAccessService $resourceAccess,
        private readonly NotificationService $notificationService,
        private readonly ActivityLogService $activityLogService,
    ) {}

    public function index(Request $request): JsonResponse
    {
        try {
            $query = BacklogItem::with(['project', 'assignedSprint', 'creator', 'convertedTask.assignee']);
            if (! $this->resourceAccess->canSeeAll($request->user())) {
                $query->where(function ($scope) use ($request) {
                    $scope->where('created_by', $request->user()->id)
                        ->orWhereIn('project_id', $this->resourceAccess->projects($request->user())->select('projects.id'));
                });
            }

            if ($request->filled('project_id')) {
                $query->where('project_id', $request->project_id);
            }
            if ($request->filled('type')) {
                $query->where('type', $request->type);
            }
            if ($request->filled('status')) {
                $query->where('status', $request->status);
            }
            if ($request->filled('priority')) {
                $query->where('priority', $request->priority);
            }

            $archiveState = $request->input('archive_state', 'active');
            if ($archiveState === 'archived') {
                $query->whereNotNull('archived_at');
            } elseif ($archiveState !== 'all') {
                $query->whereNull('archived_at');
            }

            $perPage = min(max((int) $request->input('per_page', 15), 1), 100);
            $sortBy = in_array($request->input('sort_by'), ['id', 'title', 'priority', 'status', 'created_at', 'updated_at'], true)
                ? $request->input('sort_by')
                : 'created_at';
            $sortDir = $request->input('sort_dir', 'desc');
            $items = $query->orderBy($sortBy, $sortDir)->paginate($perPage);

            return response()->json([
                'success' => true,
                'data' => BacklogItemResource::collection($items),
                'meta' => [
                    'current_page' => $items->currentPage(),
                    'last_page' => $items->lastPage(),
                    'per_page' => $items->perPage(),
                    'total' => $items->total(),
                ],
                'message' => 'لیست بکلاگ',
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'خطا در دریافت بکلاگ',
            ], 500);
        }
    }

    public function show(BacklogItem $backlogItem): JsonResponse
    {
        try {
            $backlogItem->load(['project', 'assignedSprint', 'creator']);

            return response()->json([
                'success' => true,
                'data' => new BacklogItemResource($backlogItem),
                'message' => 'اطلاعات آیتم بکلاگ',
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'خطا در دریافت اطلاعات آیتم بکلاگ',
            ], 500);
        }
    }

    public function store(StoreBacklogItemRequest $request): JsonResponse
    {
        try {
            $data = $request->validated();
            if (! empty($data['project_id'])) {
                abort_unless(
                    $this->resourceAccess->projects($request->user())->whereKey($data['project_id'])->exists(),
                    403,
                    'شما به پروژه انتخاب‌شده دسترسی ندارید.'
                );
            }
            $data['created_by'] = $request->user()->id;
            $data['status'] = 'active';
            $item = BacklogItem::create($data);
            $item->load(['project', 'assignedSprint', 'creator']);

            return response()->json([
                'success' => true,
                'data' => new BacklogItemResource($item),
                'message' => 'آیتم بکلاگ ایجاد شد',
            ], 201);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'خطا در ایجاد آیتم بکلاگ',
            ], 500);
        }
    }

    public function update(Request $request, BacklogItem $backlogItem): JsonResponse
    {
        if ($backlogItem->archived_at !== null) {
            return response()->json([
                'success' => false,
                'message' => 'بک‌لاگ آرشیوشده قابل ویرایش نیست.',
            ], 422);
        }

        $data = $request->validate([
            'title' => 'sometimes|required|string|max:255',
            'description' => 'nullable|string',
            'type' => 'sometimes|required|string|max:50',
            'project_id' => 'nullable|exists:projects,id',
            'priority' => ['nullable', Rule::in(['low', 'medium', 'high', 'urgent'])],
            'estimated_effort' => 'nullable|numeric',
            'assigned_sprint_id' => 'nullable|exists:sprints,id',
        ]);

        if (array_key_exists('project_id', $data) && $data['project_id']) {
            abort_unless(
                $this->resourceAccess->projects($request->user())->whereKey($data['project_id'])->exists(),
                403,
                'شما به پروژه انتخاب‌شده دسترسی ندارید.'
            );
        }

        try {
            $backlogItem->update([...$data, 'status' => 'active']);
            $backlogItem->load(['project', 'assignedSprint', 'creator']);

            return response()->json([
                'success' => true,
                'data' => new BacklogItemResource($backlogItem->fresh()),
                'message' => 'آیتم بکلاگ به‌روزرسانی شد',
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'خطا در به‌روزرسانی آیتم بکلاگ',
            ], 500);
        }
    }

    public function destroy(BacklogItem $backlogItem): JsonResponse
    {
        try {
            $backlogItem->delete();

            return response()->json([
                'success' => true,
                'message' => 'آیتم بکلاگ حذف شد',
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'خطا در حذف آیتم بکلاگ',
            ], 500);
        }
    }

    public function convertToTask(Request $request, BacklogItem $backlogItem): JsonResponse
    {
        $data = $request->validate([
            'assignee_id' => 'required|exists:users,id',
            'priority' => ['required', Rule::in(['low', 'medium', 'high', 'urgent'])],
            'start_date' => 'nullable|date',
            'due_date' => 'nullable|date',
            'estimated_time' => 'nullable|numeric|min:0',
        ]);

        if (! $backlogItem->project_id) {
            throw ValidationException::withMessages([
                'project_id' => 'برای تبدیل بک‌لاگ به تسک، انتخاب پروژه الزامی است.',
            ]);
        }

        if (! empty($data['start_date']) && ! empty($data['due_date']) && $data['due_date'] < $data['start_date']) {
            throw ValidationException::withMessages([
                'due_date' => 'تاریخ پایان نمی‌تواند قبل از تاریخ شروع باشد.',
            ]);
        }

        $project = Project::with('members:id')->findOrFail($backlogItem->project_id);
        abort_unless($this->resourceAccess->canAccessProject($request->user(), $project), 403);

        $assigneeId = (int) $data['assignee_id'];
        $canAssign = $this->resourceAccess->canSeeAll($request->user())
            || $assigneeId === (int) $request->user()->id
            || $assigneeId === (int) $project->project_manager_id
            || $project->members->contains('id', $assigneeId);

        if (! $canAssign) {
            throw ValidationException::withMessages([
                'assignee_id' => 'مسئول انتخاب‌شده عضو این پروژه نیست.',
            ]);
        }

        $task = DB::transaction(function () use ($backlogItem, $data, $request) {
            $lockedItem = BacklogItem::query()->lockForUpdate()->findOrFail($backlogItem->id);
            if ($lockedItem->archived_at !== null || $lockedItem->converted_to_task_id !== null) {
                throw ValidationException::withMessages([
                    'backlog_item' => 'این بک‌لاگ قبلاً به تسک تبدیل و آرشیو شده است.',
                ]);
            }

            $task = Task::create([
                'title' => $lockedItem->title,
                'description' => $lockedItem->description,
                'project_id' => $lockedItem->project_id,
                'assignee_id' => $data['assignee_id'],
                'reporter_id' => $request->user()->id,
                'created_by' => $request->user()->id,
                'priority' => $data['priority'] ?? $lockedItem->priority,
                'status' => 'todo',
                'start_date' => $data['start_date'] ?? null,
                'due_date' => $data['due_date'] ?? null,
                'estimated_time' => $data['estimated_time'] ?? null,
            ]);

            $lockedItem->update([
                'status' => 'converted',
                'converted_to_task_id' => $task->id,
                'archived_at' => now(),
            ]);

            $this->notificationService->create(
                $task->assignee_id,
                'task_assigned',
                [
                    'task_id' => $task->id,
                    'project_id' => $task->project_id,
                    'url' => '/tasks',
                    'notifiable_type' => Task::class,
                    'notifiable_id' => $task->id,
                ],
                "وظیفه جدید {$task->title} به شما اختصاص داده شد"
            );

            $this->activityLogService->log(
                $request->user()->id,
                'convert_backlog_to_task',
                "بک‌لاگ {$lockedItem->title} به وظیفه تبدیل و آرشیو شد",
                'backlog_item',
                $lockedItem->id,
                $task->project_id,
                $task->id,
                ['backlog_item_id' => $lockedItem->id, 'task_id' => $task->id]
            );

            return $task;
        });

        $task->load(['project', 'assignee', 'reporter']);

        return response()->json([
            'success' => true,
            'data' => new TaskResource($task),
            'message' => 'آیتم بک‌لاگ به وظیفه تبدیل و آرشیو شد',
        ], 201);
    }
}
