<?php

namespace App\Master;

use Carbon\Carbon;
use Illuminate\Database\Eloquent\HigherOrderBuilderProxy;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Support\HigherOrderCollectionProxy;
use Mtc\MercuryDataModels\ModelHasRole;
use Mtc\MercuryDataModels\Role;
use Mtc\MercuryDataModels\Tenant;
use Mtc\MercuryDataModels\User;
use Stancl\Tenancy\Database\Models\Domain;

class SiteManager
{
    use DispatchesJobs;

    /**
     * Add a new site record
     *
     * @param string $name
     * @param string|null $domainName
     * @return Tenant|Model
     */
    public function addSiteRecord(string $name, string $domainName = '', string $tier = ''): Tenant
    {
        $record = Tenant::query()
            ->create([
                'name' => $name,
                'tier' => $tier
            ]);

        if (!empty($domainName)) {
            $record->domains()->create(['domain' => $domainName]);
        }

        return $record;
    }

    /**
     * Get the users added to site
     *
     * @param string $siteId
     * @param string|null $search
     * @param int $perPage
     * @param int $page
     * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
     */
    public function getSiteUsers(string $siteId, ?string $search = null, int $perPage = 15, int $page = 1)
    {
        /** @var Tenant $tenant */
        $tenant = Tenant::query()->findOrFail($siteId);

        return $tenant->users()
            ->when($search, function ($query) use ($search) {
                $query->where(function ($q) use ($search) {
                    $q->where('name', 'like', "%{$search}%")
                        ->orWhere('email', 'like', "%{$search}%");
                });
            })
            ->paginate($perPage, ['*'], 'page', $page);
    }

    /**
     * Get the count of users added to site
     *
     * @param string $siteId
     * @return int
     */
    public function getSiteUserCount(string $siteId): int
    {
        return User::query()
            ->whereHas('tenants', fn($query) => $query->where('tenant_id', $siteId)->where('role', '!=', 'mtc'))
            ->count();
    }

    /**
     * Add user to site
     *
     * @param string $email
     * @param string $siteId
     * @param string $role
     * @return bool
     */
    public function addUser(string $email, string $siteId, string $role)
    {
        return new InviteManager()->invite($email, $siteId, $role);
    }

    /**
     * Remove user
     *
     * @param int $userId
     * @param string $siteId
     * @return bool
     */
    public function removeUser(int $userId, string $siteId): bool
    {
        /** @var Tenant $site */
        $site = Tenant::query()->findOrFail($siteId);

        ModelHasRole::query()
            ->where('model_type', 'user')
            ->where('model_id', $userId)
            ->where('tenant_id', $siteId)
            ->delete();

        return $site->users()->detach($userId) > 0;
    }

    /**
     * Change the role of site user
     *
     * @param string $siteId
     * @param int $userId
     * @param $newRole
     * @return bool
     */
    public function changeUserRole(string $siteId, int $userId, $newRole): bool
    {
        /** @var Tenant $site */
        $site = Tenant::query()->findOrFail($siteId);

        /** @var Role $role */
        $role = Role::query()->where('name', $newRole)->firstOrFail();

        ModelHasRole::query()
            ->where('model_type', 'user')
            ->where('model_id', $userId)
            ->where('tenant_id', $siteId)
            ->delete();

        ModelHasRole::query()
            ->insert([
                'model_type' => 'user',
                'model_id' => $userId,
                'tenant_id' => $siteId,
                'role_id' => $role->id,
            ]);

        return $site->users()->updateExistingPivot($userId, ['role' => $newRole]) > 0;
    }

    /**
     * Suspend Site
     *
     * @param Tenant $site
     * @param User $user
     * @param string $message
     * @return bool
     */
    public function suspendSite(Tenant $site, User $user, string $message = ''): bool
    {
        return $site->update([
            'suspended_at' => Carbon::now(),
            'suspended_by' => $user->id,
            'suspended_message' => $message,
        ]);
    }

    public function markLive(Tenant $site, User $user): bool
    {
        return $site->update([
            'live_at' => Carbon::now(),
            'marked_live_by' => $user->id,
        ]);
    }

    /**
     * Unsuspend site
     *
     * @param Tenant $site
     * @return bool
     */
    public function unsuspendSite(Tenant $site): bool
    {
        return $site->update([
            'suspended_at' => null,
            'suspended_by' => null,
            'suspended_message' => null,
        ]);
    }

    /**
     * Get domains registered for site
     *
     * @param Tenant $site
     * @return \Illuminate\Database\Eloquent\Collection
     */
    public function getDomains(Tenant $site)
    {
        return $site->domains()->get();
    }

    /**
     * Add a new domain record
     *
     * @param Tenant $site
     * @param string $domain
     * @return void
     */
    public function addDomain(Tenant $site, string $domain)
    {
        $site->domains()->create([
            'domain' => $domain
        ]);
    }

    /**
     * Make domain primary for site
     *
     * @param Domain $domain
     * @return void
     */
    public function makeDomainPrimary(Tenant $site, Domain $domain)
    {
        $site->domains()->update([
            'primary' => false,
            'force' => false,
        ]);

        $domain->update([
            'primary' => true,
        ]);
    }

    /**
     * Remove domain record
     *
     * @param Domain $domain
     * @return void
     */
    public function removeDomain(Domain $domain)
    {
        $domain->delete();
    }
}
