<?php

namespace Modules\Admin\app\Http\Controllers;

use App\Helper\Cache\UserJiraCacheHelper;
use App\Http\Controllers\Controller;
use App\Models\User;
use App\Services\JiraService;
use App\Traits\AnalyzeData;
use App\Traits\HasFilterRequest;
use App\Traits\HasOrderByRequest;
use App\Traits\HasSearchRequest;
use Carbon\Carbon;
use Carbon\CarbonPeriod;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Modules\Admin\app\Models\Criteria;
use Modules\Admin\app\Models\Sprint;
use Modules\Admin\app\Models\SprintCriteria;
use Modules\Admin\app\Models\UserCriteria;

class CriteriasController extends Controller
{
    use HasOrderByRequest;
    use HasFilterRequest;
    use HasSearchRequest;
    use AnalyzeData;

    protected $jiraService;

    public function __construct(JiraService $jiraService)
    {
        $this->jiraService = $jiraService;
    }

    public function getAllUserJira()
    {
        $all_users = User::all();
        $users = $this->jiraService->getUsersByEmails($all_users);
        return $users;
    }

    /**
     * Get all criterias of a sprint
     *
     * @param int $sprintId The id of the sprint
     * @return \Illuminate\Database\Eloquent\Collection|null A collection of Criteria models or null if the sprint is not found
     */
    public function getCriteriasForSprint($sprintId)
    {
        $userInfo = auth('admins')->user();
        $sprint = Sprint::with('criterias')->find($sprintId);
        if (!$sprint) {
            // $allUser = self::getAllUserJira();
            $allUser = UserJiraCacheHelper::getCacheSetting();
            $issues = $this->jiraService->getAllIssueByIdSprint($sprintId);

            // Collect unique assignees
            $uniqueUsers = [];
            if ($issues) {
                $issues = $issues["issues"];
                foreach ($issues as $issue) {
                    $assignee = $issue["fields"]["assignee"];
                    if ($assignee && !in_array($assignee["accountId"], $uniqueUsers)) {
                        $uniqueUsers[] = $assignee["accountId"];
                    }
                }
            }

            // Filter users based on unique assignees
            $filteredObjects = array_filter($allUser, function ($user) use ($uniqueUsers) {
                // return in_array($user[0]['accountId'], $uniqueUsers);
                return in_array($user[0]->accountId, $uniqueUsers);
            });

            // Map filtered users to desired format
            $arrayUsers = array_map(function ($item) {
                // return [
                //     'accountId' => $item[0]['accountId'],
                //     'emailAddress' => $item[0]['emailAddress'],
                //     'displayName' => $item[0]['displayName'],
                // ];
                return [
                    'accountId' => $item[0]->accountId,
                    'emailAddress' => $item[0]->emailAddress,
                    'displayName' => $item[0]->displayName,
                ];
            }, $filteredObjects);

            // Get criteria for sprint and member
            $criteriasSprint = Criteria::where('type', "SPRINT")->get()->toArray();
            $members = Criteria::where('type', "MEMBER")->get()->toArray();

            // Merge user information with criteria
            $result = [];
            foreach ($arrayUsers as $user) {
                foreach ($members as $member) {
                    $result[] = array_merge($user, $member);
                }
            }

            // Map result to final format
            $users = array_map(function ($item) use ($userInfo) {
                return [
                    "user_id" => $item['accountId'],
                    "user" => $item['displayName'],
                    "user_email" => $item['emailAddress'],
                    "criteria_id" => $item['id'],
                    "point" => "",
                    "note" => "",
                    "created_by" => $userInfo->name,
                    "name" => $item['name'],
                    "description" => $item['description'],
                    "criteria_description" => $item['description'],
                ];
            }, $result);


            $criterias = array_map(function ($item) {
                $item["expect"] = "";
                $item["actual"] = "";
                $item["note"] = "";
                $item["point"] = "";
                return $item;
            }, $criteriasSprint);

            $data = [
                "criterias" => $criterias,
                "users" => $users
            ];
        } else {
            $users = $sprint->users()->get();
            // echo json_encode($sprint);
            // dd();
            $criterias = array_map(function ($item) {
                $item["expect"] = $item["pivot"]["expect_result"];
                $item["actual"] = $item["pivot"]["actual_result"];
                $item["note"] = $item["pivot"]["note"];
                $item["point"] = $item["pivot"]["point"];
                unset($item["pivot"]); // Use unset() instead of delete
                return $item;
            }, $sprint->criterias->toArray());

            $data = [
                "id" => $sprint->id,
                "name" => $sprint->name,
                "point" => $sprint->point,
                "project_id" => $sprint->project_id,
                "start_date" => $sprint->start_date,
                "end_date" => $sprint->end_date,
                "complete_date" => $sprint->complete_date,
                "criterias" => $criterias,
                "users" => $users
            ];
        }
        return AbstractController::ResultSuccess($data);
    }

    public function convertDataReponse($criterias)
    {
        $data = [];
        foreach ($criterias as $key => $criteria) {
            $data[$key]["criteria_name"] = $criteria->name;
            $data[$key]["description"] = $criteria->description;
            $data[$key]["type"] = $criteria->type;
            foreach ($criteria->users as $keyChild => $user) {
                $dataChild[$keyChild]["user_id"] = $user->id;
                $dataChild[$keyChild]["user_name"] = $user->name;
                $dataChild[$keyChild]["email"] = $user->email;
                $dataChild[$keyChild]["point"] = $user->pivot->point;
                $dataChild[$keyChild]["note"] = $user->pivot->note;
                $dataChild[$keyChild]["sprint_id"] = $user->pivot->sprint_id;
            }
            $data[$key]['users'] = $dataChild;
        }

        return $data;
    }
    /**
     * Get all criterias of a user
     *
     * @param int $userId The id of the user
     * @return \Illuminate\Database\Eloquent\Collection|null A collection of Criteria models or null if the user is not found
     */
    public function getCriteriasForUser($userId)
    {
        $criterias = Criteria::whereHas('users', function ($query) use ($userId) {
            $query->where('user_id', $userId);
        })->with(['users' => function ($query) use ($userId) {
            $query->where('user_id', $userId);
        }])->get();

        $data = self::convertDataReponse($criterias);
        return AbstractController::ResultSuccess($data);
    }

    /**
     * Get all criterias of a user for a sprint
     *
     * @param int $userId The id of the user
     * @param int $sprintId The id of the sprint
     * @return \Illuminate\Database\Eloquent\Collection|null A collection of Criteria models or null if the user or sprint is not found
     */
    public function getCriteriasForUserBySprint($userId, $sprintId)
    {
        $criterias = Criteria::whereHas('users', function ($query) use ($userId, $sprintId) {
            $query->where('user_id', $userId)->where('sprint_id', $sprintId);
        })->with(['users' => function ($query) use ($userId, $sprintId) {
            $query->where('user_id', $userId)->where('sprint_id', $sprintId);
        }])->get();

        $data = self::convertDataReponse($criterias);
        return AbstractController::ResultSuccess($data);
    }

    /**
     * Get all criterias
     *
     * @return \Illuminate\Database\Eloquent\Collection A collection of Criteria models
     */
    public function getAllCriterias(Request $request)
    {
        if ($request->type) {
            $responseData = Criteria::where('type', $request->type)->get();
        } else {
            $responseData = Criteria::all();
        }
        return AbstractController::ResultSuccess($responseData);
    }

    public function updateCriteriasForSprint($sprintId, Request $request)
    {
        $userInfo = auth('admins')->user();
        // Validate dữ liệu đầu vào
        $validated = $request->validate([
            'name' => 'required|string',
            'project_id' => 'required|integer',
            'criterias' => 'required|array',
            'users' => 'required|array',
        ]);
        $sprintId = (int)$sprintId;

        // Sử dụng transaction để đảm bảo tính toàn vẹn dữ liệu
        DB::beginTransaction();
        try {
            // Kiểm tra xem Sprint có tồn tại không
            $sprint = Sprint::find($sprintId);

            if ($sprint) {
                // Nếu tồn tại, xóa các liên kết hiện tại
                $sprint->sprintsCriterias()->delete();
                $sprint->usersCriterias()->delete();

                // Cập nhật thông tin Sprint nếu cần
                $sprint->update([
                    'name' => $validated['name'],
                    'project_id' => $validated['project_id'],
                    'point' => $request->finalPoint ?? "",

                    'start_date' => $request->start_date,
                    'end_date' => $request->end_date,
                    'complete_date' => $request->complete_date,

                ]);
            } else {
                // Nếu không tồn tại, tạo mới Sprint
                $sprint = Sprint::create([
                    'id' => $sprintId,
                    'name' => $validated['name'],
                    'project_id' => $validated['project_id'],
                    'point' => $request->finalPoint ?? "",

                    'start_date' => $request->start_date,
                    'end_date' => $request->end_date,
                    'complete_date' => $request->complete_date,
                ]);
            }

            // Thêm lại các liên kết sprints_criterias
            foreach ($validated['criterias'] as $criteria) {
                SprintCriteria::create([
                    'sprint_id' => $sprintId,
                    'criteria_id' => $criteria['id'],
                    'point' => $criteria['point'] ?? "",
                    'expect_result' => $criteria['expect'] ?? "",
                    'actual_result' => $criteria['actual'] ?? "",
                    'note' => $criteria['note'] ?? "",
                    'created_by' => $userInfo->name ?? "",
                ]);
            }

            // Thêm lại các liên kết users_criterias
            foreach ($validated['users'] as $userCriteria) {
                UserCriteria::create([
                    'user_email' => $userCriteria['user_email'],
                    'criteria_id' => $userCriteria['criteria_id'],
                    'sprint_id' => $sprintId,
                    'point' => $userCriteria['point'] ?? "",
                    'note' => $userCriteria['note'] ?? "",
                    'created_by' => $userCriteria['created_by'] ?? "",
                ]);
            }

            DB::commit();
            return AbstractController::ResultSuccess("Update sprint success");
        } catch (\Exception $e) {
            DB::rollBack();

            return AbstractController::ResultError("Update sprint failed: " . $e->getMessage());
        }
    }
}
