<?php

namespace App\Services;

use App\Enums\JobOfferStatusEnum;
use App\Enums\WatchlistTypeEnum;
use App\Exceptions\ApiHttpException;
use App\Models\AccountMember;
use App\Models\CompanyProfile;
use App\Models\JobOffer;
use App\Models\Project;
use App\Models\Result;
use App\Models\User;

class ProfilesService
{
    /**
     * Get profiles
     *
     * @param array $params
     * @return Paginator
     */
    public function getProfiles(array $params, $user = null)
    {
        $itemsPerPage = $params['itemsPerPage'] ?? 5;
        $page = $params['page'] ?? 1;
        $filters = $params['filters'] ?? [];
        $orderDir = $params['orderDir'] ?? 'desc';

        $query = CompanyProfile::with([
            'companySpecialisations' => function ($query) {
                $query->full();
            },
            'offices' => function ($query) {
                $query->with(['country' => function ($query) {
                    $query->full();
                }])->where('is_main_office', true)->limit(1);
            },
            'account.subscriptions',
        ])->where('is_active', true)
            ->where(function ($query) {
                $query->whereDoesntHave('account')
                    ->orWhereHas('account.subscriptions', function ($subscriptionQuery) {
                        $subscriptionQuery->active();
                    });
        });

        $query->with(['watchlists' => function ($query) use ($user) {
            $query->where('user_id', $user ? $user->id : null)
                ->where('type', WatchlistTypeEnum::COMPANY_PROFILES->value);
        }]);

        if (!empty($filters['specialisation'])) {
            $query->whereHas('companySpecialisations', function ($query) use ($filters) {
                $query->whereIn('id', $filters['specialisation']);
            });
        }

        if (!empty($filters['countries'])) {
            $query->whereHas('offices', function ($query) use ($filters) {
                $query->whereHas('country', function ($query) use ($filters) {
                    $query->whereIn('iso2', $filters['countries']);
                });
            });
        }

        if (!empty($filters['search'])) {
            $query->where(function ($query) use ($filters) {
                $query->where('name', 'like', '%' . $filters['search'] . '%');
            });
        }

        $profiles = $query->orderBy('id', $orderDir)
            ->paginate($itemsPerPage, ['*'], 'page', $page);

        return $profiles;
    }

    /**
     * Get profile by ID
     *
     * @param int $id
     * @return CompanyProfile
     */
    public function getProfile(int $id)
    {
        $profile = CompanyProfile::with([
            'companySpecialisations' => function ($query) {
                $query->full();
            },
            'offices',
            'jobOffers' => function ($query) {
                $query
                    ->where('status', JobOfferStatusEnum::ACTIVE)
                    ->where('active_until', '>=', now());
            },
            'members' => function ($query) {
                $query->where('status', AccountMember::STATUS_ACCEPTED);
            },
            'projects' => function ($query) {
                $query->orderBy('project_date', 'desc')->with('images');
            },
            'coordinationGroupMembers',
            'resultEntities',
            'account.subscriptions',
        ])
        ->where('is_active', true)
        ->where(function ($query) {
            $query->whereDoesntHave('account')
                ->orWhereHas('account.subscriptions', function ($subscriptionQuery) {
                    $subscriptionQuery->active();
                });
        })
        ->where('id', $id)
        ->first();

        if (!$profile) {
            throw new ApiHttpException(404, trans('frontend.exception_profile_not_found'));
        }

        return $profile;
    }

    /**
     * Get profile job detail
     *
     * @param int $profileId
     * @param int $jobId
     * @return JobOffer|null
     */
    public function getProfileJob(int $profileId, int $jobId)
    {
        $jobProfile = JobOffer::where('id', $jobId)
            ->where('company_profile_id', $profileId)
            ->where('status', JobOfferStatusEnum::ACTIVE)
            ->where('active_until', '>=', now())
            ->first();

        if (!$jobProfile) {
            throw new ApiHttpException(404, trans('frontend.exception_job_profile_not_found'));
        }

        return $jobProfile;
    }

    /**
     * Get profile team member detail
     *
     * @param int $profileId
     * @param int $userId
     * @return AccountMember|null
     */

    public function getProfileTeamMember(int $profileId, int $userId)
    {
        $teamMemberProfile = AccountMember::with([
            'user',
            'account.address.country',
        ])
        ->where('user_id', $userId)
        ->whereHas('account.profile', function ($query) use ($profileId) {
            $query->where('id', $profileId);
        })
        ->where('status', AccountMember::STATUS_ACCEPTED)
        ->first();


        if (!$teamMemberProfile) {
            throw new ApiHttpException(404, trans('frontend.exception_team_member_profile_not_found'));
        }

        return $teamMemberProfile;
    }

    /**
     * Get profile project detail
     *
     * @param int $profileId
     * @param int $projectId
     * @return Project|null
     */

    public function getProfileProject(int $profileId, int $projectId)
    {
        $profileProject = Project::where('id', $projectId)
            ->where('company_profile_id', $profileId)
            ->first();

        if (!$profileProject) {
            throw new ApiHttpException(404, trans('frontend.exception_project_not_found'));
        }

        return $profileProject;
    }

    /**
     * Get user jury members
     *
     * @param User $user
     * @return Result|null
     */

    public function getUserJuryMembers($user)
    {
        $resultJuryMembers = Result::whereHas('juryGroups.juryGroupMembers', function ($query) use ($user) {
            $query->where('user_id', $user->id);
        })
        ->with(['juryGroups' => function ($query) use ($user) {
            $query->whereHas('juryGroupMembers', function ($q) use ($user) {
                $q->where('user_id', $user->id);
            });
        }])
        ->get();

        return $resultJuryMembers;
    }

    /**
     * Get user result winners
     *
     * @param User $user
     * @return Result|null
     */

    public function getUserResultWinners($user)
    {
        $resultWinners = Result::whereHas('winners.entities.authors', function ($query) use ($user) {
            $query->where('user_id', $user->id);
        })->orWhereHas('winners.entities.contributors', function ($query) use ($user) {
            $query->where('user_id', $user->id);
        })
        ->with(['winners' => function ($query) use ($user) {
            $query->whereHas('entities.authors', function ($q) use ($user) {
                $q->where('user_id', $user->id);
            })->orWhereHas('entities.contributors', function ($q) use ($user) {
                $q->where('user_id', $user->id);
            });
        }])
        ->get();

        return $resultWinners;
    }

    /**
     * Get user projects
     *
     * @param User $user
     * @return Project|null
     */
    public function getUserProjects($user)
    {
        $userProjects = Project::where('user_id', $user->id)->get();

        return $userProjects;
    }

    /**
     * Get basic user profile (for users without an account)
     *
     * @param int $userId
     * @return User
     */
    public function getBasicUser(int $userId)
    {
        $user = User::with(['profileRole', 'profileSpecialisation', 'cvEntries'])
            ->where('id', $userId)
            ->first();

        if (!$user) {
            throw new ApiHttpException(404, trans('frontend.exception_user_not_found'));
        }

        if (!$user->isBasicUser()) {
            throw new ApiHttpException(403, trans('frontend.exception_user_has_account'));
        }

        return $user;
    }
}
