<?php

namespace App\Libs\Services;

use App\Models\Domain;
use App\Models\Member;
use App\Services\MicrosoftGraph\UserMembershipService;
use Illuminate\Support\Facades\DB;
use Illuminate\Pagination\Paginator;
use Illuminate\Support\Str;
use Throwable;

class MemberService
{
    protected $userMembershipService;

    public function __construct(UserMembershipService $userMembershipService)
    {
        $this->userMembershipService = $userMembershipService;
    }
    /**
     * Get the member list for the backoffice grid
     *
     * @param $page
     * @param $rowCount
     * @param $sort
     * @param $search
     *
     * @return array
     */
    public function getMemberGridList($page, $rowCount, $sort, $search, $type, $status, $wg, $committee, $legalCommittee, $legalOpinions)
    {
        Paginator::currentPageResolver( function () use ($page) {
            return $page;
        });

        if (!empty($search)) {
            $query = Member::where(function ($query) use ($search) {
                $query->orWhere('name', 'like', "%{$search}%")
                    ->orWhere('member_type', 'like', "%{$search}%")
                    ->orWhere('state', 'like', "%{$search}%");
            });
        } else {
            $query = Member::query();
        }

        if (!empty($type)) {
            $query->where('member_type', $type);
        }

        if (!empty($status)) {
            $query->where('state', $status);
        }

        if (!empty($legalCommittee)) {
            $query->where('legal_committee', $legalCommittee);
        }

        if (!empty($legalOpinions)) {
            $query->where('legal_opinions', $legalOpinions);
        }

        if (!empty($wg) && $wg > 0) {
            $query->whereExists(function ($query) use ($wg) {
                $query->select('work_group_id')
                    ->from('member_work_group')
                    ->where('work_group_id', $wg)
                    ->whereRaw('member_work_group.member_id = members.id');
            });
        }

        if (!empty($committee) && $committee > 0) {
            $query->whereExists(function ($query) use ($committee) {
                $query->select('committee_id')
                    ->from('committee_member')
                    ->where('committee_id', $committee)
                    ->whereRaw('committee_member.member_id = members.id');
            });
        }

        if (empty($sort)) {
            $rows = $query->paginate($rowCount);
        } else {
            foreach ($sort as $field => $direction) {
                if(empty($direction) || !Str::is(strtolower($direction),"desc")){
                    $orderDirection = "asc";
                } else {
                    $orderDirection = $direction;
                }
                $rows = $query->orderBy($field, strtolower($orderDirection))->paginate($rowCount);
                break;
            }
        }

        return [
            "total"             => $rows->total(),
            "current"           => $rows->currentPage(),
            "rowCount"          => $rowCount,
            "rows"              => $rows->getCollection()
        ];
    }

    public function createMember($data)
    {
        $member = new Member();
        return $this->_fillMemberData($member, $data);
    }

    public function editMember($memberId, $data)
    {
        $member = Member::findOrFail($memberId);
        return $this->_fillMemberData($member, $data);
    }

    protected function _fillMemberData(Member $member, $data)
    {
        DB::beginTransaction();

        try {
            $loggedUser = BackendUserService::getLoggedUser();

            $member->backend_user_id = $loggedUser->id;
            $member->name = $data["name"];
            $member->notes = $data["notes"];
            $member->member_type = $data['member_type'];
            $member->state = $data['state'];
            $member->country_id = $data["country_id"];
            $member->legal_committee = !empty($data["legal_committee"]) ? 1 : 0;

            $member->user_permission_level = !empty($data["user_permission_level"]) ? 1 : 0;

            $legalOpinionsResult = 0;
            if (!empty($data['legal_opinions'])) {
                $legalOpinionsResult = 1;
            } else if (!empty($data["legal_committee"])) {
                $legalOpinionsResult = 1;
            } else if ($data['member_type'] === 'noType') {
                $legalOpinionsResult = 1;
            }

            $member->legal_opinions = $legalOpinionsResult;

            $images_array = json_decode($data["logo_id"]);
            if (!empty($data["logo_id"]) && count($images_array)) {
                $member->logo_id = $images_array[0];
            }

            $member->save();

            //Committee
            $committees = [];
            foreach ($data['committees'] as $com) {
                array_push($committees, $com);
            }
            $member->committees()->sync($committees);

            //WG
            $workGroups = [];
            foreach ($data['workGroups'] as $wg) {
                array_push($workGroups, $wg);
            }
            $member->workGroups()->sync($workGroups);

            // Sync user memberships based on member membership changes
            // This will remove users from committees/workgroups that their member is no longer part of
            $this->userMembershipService->syncUsersBasedOnMemberMemberships($member->id);

            //Domains
            $currentDomains = Domain::where('member_id', $member->id)->pluck('domain')->toArray();

            foreach ($data['domains'] as $domainName) {
                if (empty($domainName)) {
                    continue;
                }

                $domainExists = in_array($domainName, $currentDomains);

                if ($domainExists) {
                    $currentDomains = array_diff($currentDomains, [$domainName]);
                } else {
                    $domain = new Domain();
                    $domain->domain = $domainName;
                    $domain->member_id = $member->id;
                    $domain->save();
                }
            }

            foreach ($currentDomains as $domainName) {
                Domain::where('member_id', $member->id)
                    ->where('domain', $domainName)
                    ->delete();
            }

            DB::commit();
        } catch (Throwable $e) {
            DB::rollback();
            throw($e);
        }

        return $member;
    }

    public function list(array $searchData) {
        $orderDir = $searchData['orderDir'] ? $searchData['orderDir'] : 'asc';

        $query = Member::where('state', 'active');

        if ($searchData['committeeId']) {
            $query->where(function ($query) use ($searchData) {
                $query->whereExists(function ($query) use ($searchData) {
                        $query->select(DB::raw(1))
                            ->from('committee_member')
                            ->whereRaw('committee_member.member_id = members.id')
                            ->where('committee_member.committee_id', $searchData['committeeId']);
                    });
            });
        } else if ($searchData['workGroupId']) {
            $query->where(function ($query) use ($searchData) {
                $query->whereExists(function ($query) use ($searchData) {
                        $query->select(DB::raw(1))
                            ->from('member_work_group')
                            ->whereRaw('member_work_group.member_id = members.id')
                            ->where('member_work_group.work_group_id', $searchData['workGroupId']);
                    });
            });
        }

        switch ($searchData['orderBy']) {
            default:
                # name
                $query->orderBy('name', $orderDir);
                break;
        }

        $members = $query->get();

        return $members;
    }

    public function findById(string $id): ?Member {
        $query = Member::where('state', 'active')
            ->where('id', $id);

            $query->with([
                'country' => function($query) {
                    $query->full()->with('flag');
                },
                'domains',
                'workGroups' => function($query) {
                    $query->full()->select('*');
                }
            ]);

        return $query->first();
    }

    public function findByIdCommittees(string $id): ?Member {
        $query = Member::where('state', 'active')
            ->where('id', $id);

        $query->with([
            'committees' => function ($query) {
                $query
                    ->full()
                    ->with(['workGroups' => function ($query) {
                        $query->full();
                    }]);
            }]
        );

        return $query->first();
    }

}
