<?php

namespace App\Services;

use App\Enums\GenericStatusEnum;
use App\Exceptions\InvalidSubscriberAction;
use App\Models\CommunitySubscriber;
use App\Models\CommunitySuspension;
use App\Models\User;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;

trait CommunitySubscriberService
{
   /**
    * Store new record
    *
    * @param array $data
    * @return Builder|Model
    */
   public static function store(array $data): Model|Builder
   {
      return CommunitySubscriber::query()->create($data);
   }

   /**
    * Update existing record
    *
    * @param array $data
    * @return mixed
    */
   public function updateService(array $data): mixed
   {
      return tap($this)->update($data);
   }

   /**
    * Add user to community subscribers
    *
    * @param array $data
    * @return Builder|Model
    */
   public static function addSubscriber(array $data): Model|Builder
   {
      return self::store([
         "is_admin" => GenericStatusEnum::disable->value,
         "user_id" => $data["user_id"],
         "community_id" => $data["community_id"],
      ]);
   }

   /**
    * Check if user is community admin or already a subscriber
    *
    * @param string $adminType
    * @param int $userId
    * @param int $communityId
    * @return Model|Builder|null
    */
   public static function checkIsCommunityAdminOrAlreadySubscriber(string $adminType, int $userId, int $communityId): Model|Builder|null
   {
      return
         CommunitySubscriber::query()
            ->where("is_admin", $adminType)
            ->where("user_id",  $userId)
            ->where('community_id', $communityId)
            ->first();
   }

   /**
    * Get community subscriber
    *
    * @param int $userId
    * @param int $communityId
    * @return Model|Builder|null
    */
   public static function getCommunitySubscriber(int $userId, int $communityId): Model|Builder|null
   {
      return CommunitySubscriber::query()->where("user_id",  $userId)->where('community_id', $communityId)->first();
   }

   /**
    * Get the number of subscribers
    *
    * @param int $communityId
    * @return int
    */
   public static function numberOfSubscribers(int $communityId): int
   {
      return CommunitySubscriber::query()->where('community_id', $communityId)->count();
   }

   /**
    * Marks as Admin or simple member
    *
    * @param array $data
    * @return CommunitySubscriber
    * @throws InvalidSubscriberAction
    */
   public function markAsAdminOrMember(array $data): CommunitySubscriber
   {
      try {
         $communitySubscriber = $this;

         /** @var User $user */
         $user = auth()->user();

         // Check if action is performed by community admin
         $isCommunityAdmin = CommunitySubscriber::checkIsCommunityAdminOrAlreadySubscriber(GenericStatusEnum::enable->value, $user->{"id"}, $data["community_id"]);

         if ($isCommunityAdmin == null) {
            throw new InvalidSubscriberAction(__("errors.invalid_subscriber_action"));
         }

         // Check if action is to mark member as Admin
         if($data['action'] == config("torryme.community_subscriber_action.mark_as_admin")) {
            // Mark member as Admin
            $communitySubscriber->updateService([
               "is_admin" => GenericStatusEnum::enable->value
            ]);
         } else {
            // Check if Admin is trying to change to member by himself and throw exception
            if($isCommunityAdmin->{"user_id"} == $data["user_id"]) {
               throw new InvalidSubscriberAction(__("errors.invalid_subscriber_action"));
            }
            // Mark Admin as member
            $communitySubscriber->updateService([
               "is_admin" => GenericStatusEnum::disable->value
            ]);
         }

         $result = $communitySubscriber->refresh();
      } catch (\Exception $exception) {
         log_debug($exception, 'CommunitySubscriberService::markAsAdminOrMember');
         throw $exception;
      }

      return $result;
   }

   /**
    * Delete community subscriber
    *
    * @param array $data
    * @return CommunitySubscriber
    * @throws InvalidSubscriberAction
    */
   public function deleteSubscriber(array $data): CommunitySubscriber
   {
      try {
         $subscriber = $this;

         /** @var User $user */
         $user = auth()->user();

         // Check if action is performed by community admin
         $isCommunityAdmin = CommunitySubscriber::checkIsCommunityAdminOrAlreadySubscriber(GenericStatusEnum::enable->value, $user->{"id"}, $data["community_id"]);

         if ($isCommunityAdmin == null) {
            throw new InvalidSubscriberAction(__("errors.invalid_subscriber_action"));
         }

         //Delete subscriber
         $subscriber->delete();
      } catch (\Exception $exception) {
         log_debug($exception, 'CommunitySubscriberService::deleteSubscriber');
         throw $exception;
      }

      return $subscriber;
   }

   /**
    * Leave community
    *
    * @param int $communityId
    * @return CommunitySubscriber
    * @throws InvalidSubscriberAction
    */
   public static function leaveCommunity(int $communityId): CommunitySubscriber
   {
      try {
         /** @var User $user */
         $user = auth()->user();

         /** @var CommunitySubscriber $communitySubscriber */
         $communitySubscriber = CommunitySubscriber::getCommunitySubscriber($user->{"id"}, $communityId);

         if ($communitySubscriber == null) {
            throw new InvalidSubscriberAction(__("errors.unknown_error"));
         }

         // Delete community subscription
         $communitySubscriber->delete();

      } catch (\Exception $exception) {
         log_debug($exception, "CommunitySubscriberService::leaveCommunity");
         throw $exception;
      }

      return $communitySubscriber;
   }

   /**
    * Get subscriber community suspension
    *
    * @return Model|Builder|null
    */
   public function lastCommunitySuspension(): Model|Builder|null
   {
      return CommunitySuspension::query()->where("community_id", $this->{"community_id"})
                                 ->where("user_id", $this->{"user_id"})
                                 ->orderByDesc("created_at")
                                 ->first();
   }

}
