<?php

namespace Modules\Deal\Services;

use Illuminate\Support\Facades\DB;
use Mcamara\LaravelLocalization\Facades\LaravelLocalization;
use Modules\Deal\Interfaces\DealRepositoryInterface;
use Modules\Deal\Models\Deal;
use Modules\MainService\Views\ViewFactory;
use Modules\User\Enums\UserRoleEnum;
use Modules\Deal\Enums\DealStatusEnum;
use App\Jobs\SendMailJob;
use Modules\User\Services\UserService;
use Modules\Target\Services\TargetService;
use Modules\Deal\Mails\ChangeStatusMail;
use Modules\Deal\Mails\DeadlineReminderMail;
use Modules\Deal\Mails\WonCelebrateMail;

class DealService
{
    private string $veiwDirectoryMail = 'admin.deals.mails.';
    public function __construct(
        private UserService $userService,
        private TargetService $targetService,
        private DealRepositoryInterface $dealRepository,
        private ViewFactory $viewFactory
    ){}

    public function renderView($request = [])
    {
        $request['deals'] = $this->get($request);
        return $this->render($request);
    }

    public function render($request = [])
    {
        return $this->viewFactory
            ->render($request['view'])
            ->renderView($request);
    }

    public function get(array $request = [])
    {
        $builder = $this->dealRepository->get($request);

        if (@$request['title'])
        {
            $builder->where('sd.title', 'LIKE', '%'.$request['title'].'%');
        }

        if (@$request['year'])
        {
            $builder->whereYear('start_date',$request['year']);
        }
        if (@$request['month'])
        {
            $builder->where('month',$request['month']);
        }

        if (@$request['amount'])
        {
            $builder->where('amount',$request['amount']);
        }

        if (@$request['start_date'])
        {
            $builder->where('start_date',$request['start_date']);
        }

        if (@$request['end_date'])
        {
            $builder->where('end_date',$request['end_date']);
        }

        if (isset($request['typeStatus']))
        {
            $builder->where('deals.status',$request['typeStatus']);
        }

        if (@$request['company'])
        {
            $builder->whereHas('company.currentDescription',function($query) use($request){
                $query->where('title','LIKE', '%'.$request['company'].'%');
            });
        }

        if (@$request['product'])
        {
            $builder->whereHas('product.currentDescription',function($query) use($request){
                $query->where('title','LIKE', '%'.$request['product'].'%');
            });
        }

        if (@$request['contact_list'])
        {
            $builder->whereHas('contactList.currentDescription',function($query) use($request){
                $query->where('title','LIKE', '%'.$request['contact_list'].'%');
            });
        }

        if(@$request['employeeFilter'])
        {
            if($request['employeeFilter']->role == UserRoleEnum::Head_Department->value)
            {
                $builder->where(function ($q) use ($request) {
                    $q->where('employee_id', $request['employeeFilter']->id)
                    ->orWhereHas('employee', function ($query) use ($request) {
                        $query->where('manager_id', $request['employeeFilter']->id);
                    });
                });
            }
            else
            {
                $builder->where('employee_id',$request['employeeFilter']->id);
            }
        }

        if (@$request['employee'])
        {
            $builder->whereHas('employee',function($query) use($request){
                $query->where('name','LIKE', '%'.$request['employee'].'%');
            });
        }

        if (@$request['company_id'])
        {
            $builder->where('company_id',$request['company_id']);
        }

        if (@$request['sector_id'])
        {
            $builder->where('sector_id',$request['sector_id']);
        }

        if (@$request['employee_id'])
        {
            $builder->where('employee_id',$request['employee_id']);
        }

        if (@$request['employeeId'])
        {
            $builder->where('employee_id',$request['employeeId']);
        }
        if (@$request['done_dates'])
        {
            $builder->whereDate('done_date','>=',$request['done_dates']['start_date'])->whereDate('done_date','<=',$request['done_dates']['end_date']);
        }

        if (@$request['deal_id'])
        {
            if ($request['deal_id'] == 'main')
            {
                $builder->whereNull('deals.deal_id');
            }
            elseif ($request['deal_id'] == 'sub')
            {
                $builder->whereNotNull('deals.deal_id');
            }
            else
            {
                $builder->where('deal_ids.deal_id',$request['deal_id']);
            }
        }

        if (@$request['date_from'])
        {
            $builder->whereDate('deals.created_at', '>=', $request['date_from']);
        }

        if (@$request['date_to'])
        {
            $builder->whereDate('deals.created_at', '<=', $request['date_to']);
        }
        if(@$request['kanban'])
        {
            if (isset($request['status']))
            {
                if (@$request['status'] == 0)
                {
                    $builder->whereHas('subTrashed');
                }
                else
                {
                    $builder->whereHas('sub');
                }
            }
        }
        else
        {
            if (isset($request['status']))
            {
                if (@$request['status'] == 0)
                {
                    $builder->onlyTrashed();
                }
            }
        }

        if (@$request['orderBy'])
        {
            if($request['orderBy']['key'] == 'employee')
            {
                $builder
                    ->join('users AS us', 'deals.employee_id', 'us.id')
                    ->addSelect('us.name as employee_name',)
                    ->orderBy('employee_name', $request['orderBy']['value']);
            }
            elseif($request['orderBy']['key'] == 'company')
            {
                $builder
                    ->join('company_descriptions AS cd', 'deals.company_id', 'cd.company_id')
                    ->where('local', LaravelLocalization::getCurrentLocale())
                    ->addSelect('cd.title as company_name',)
                    ->orderBy('company_name', $request['orderBy']['value']);
            }
            elseif($request['orderBy']['key'] == 'product')
            {
                $builder
                    ->join('product_descriptions AS cd', 'deals.product_id', 'cd.product_id')
                    ->where('local', LaravelLocalization::getCurrentLocale())
                    ->addSelect('cd.title as product_name',)
                    ->orderBy('product_name', $request['orderBy']['value']);
            }
            elseif($request['orderBy']['key'] == 'contact_list')
            {
                $builder
                    ->join('contact_list_descriptions AS cd', 'deals.contact_list_id', 'cd.contact_list_id')
                    ->where('local', LaravelLocalization::getCurrentLocale())
                    ->addSelect('cd.title as contact_list_name',)
                    ->orderBy('contact_list_name', $request['orderBy']['value']);
            }
            else
            {
                $builder->orderBy($request['orderBy']['key'],$request['orderBy']['value']);
            }
        }
        else
        {
            $builder->orderBy('id','DESC');
        }

        if (@$request['paginate'])
        {
            $deals= $builder->paginate(50);
        }
        elseif(@$request['sum'])
        {
            $deals = $builder->sum($request['sum']);
        }
        elseif(@$request['count'])
        {
            $deals = $builder->count();
        }
        elseif(@$request['groupBy'])
        {
            if($request['groupBy'] == 'month')
            {
                $deals = $builder
                    ->select(
                        $request['groupBy'],
                        DB::raw('SUM(amount) as total_deals')
                     )
                     ->reorder()
                    ->groupBy($request['groupBy'])
                    ->get()
                    ->keyBy($request['groupBy'])     
                    ->toArray();
            }
            elseif($request['groupBy'] == 'closed_at')
            {
                $deals = $builder
                    ->whereNotNull('closed_at')
                    ->select(
                        DB::raw('MONTH(closed_at) as month'),
                        DB::raw('COUNT(*) as count')
                     )
                     ->reorder()
                    ->groupBy(DB::raw('MONTH(closed_at)'))
                    ->get()
                    ->keyBy('month')     
                    ->toArray();
            }
        }
        else
        {
            $deals=$builder->get();
        }
        return $deals;
    }
    public function checkItem($id)
    {
        $deal = $this->dealRepository->checkItem($id);
        return $deal;
    }

    public function getItem($id)
    {
        $deal = $this->dealRepository->getItem($id);

        return $deal;
    }

    public function getItemTrashed($id)
    {
        $deal = $this->dealRepository->getItemTrashed($id);
        return $deal;
    }

    public function payments(int $deal_id)
    {
        return $this->dealRepository->payments($deal_id);
    }

    public function create(array $request): Deal
    {
        if(($request['deal_status_id'] ?? null) == 1)
        {
            $request['done_date'] = date('Y-m-d H:i:s');
        }
        if(in_array($request['status'] , DealStatusEnum::finished()) )
        {
            $request['closed_at'] = date('Y-m-d H:i:s');
        }
        $deal = $this->dealRepository->create($request);
        $this->dealRepository->saveData($request,$deal->id);
        $this->dealRepository->savePayments($request,$deal->id);
        $this->dealRepository->saveLog($request,$deal->id);
        $this->ChangeStatus($deal);
        if($deal->status == DealStatusEnum::Confirmed->value)
        {
            $this->WonCelebrate($deal,$deal->employee->email);
            
            if($deal->employee->manager_id)
            {
                $this->WonCelebrate($deal,$deal->employee->manager->email);
                
            }
            $this->CheckTargetAchieved($deal->employee);
            
        }
        return $deal;
    }
    public function update(array $request,int $id): Deal
    {
        $deal = $this->checkItem($id);
        $old_status = $deal->status;
        if(@$request['deal_status_id'])
        {
            if(($request['deal_status_id'] ?? null) == 1 && $deal->deal_status_id != 1)
            {
                $request['done_date'] = date('Y-m-d H:i:s');
            }
        }
        if(in_array($request['status'] , DealStatusEnum::finished()) && $request['status'] != $deal->status )
        {
            $request['closed_at'] = date('Y-m-d H:i:s');
        }

        $deal = $this->dealRepository->update($request,$deal);
        if(@$request['title_en'])
        {
            $this->dealRepository->saveData($request,$deal->id);
            $this->dealRepository->savePayments($request,$deal->id);
            $this->dealRepository->saveLog($request,$deal->id);
        }
        if($request['status'] != $old_status)
        {
            
            $this->ChangeStatus($deal);
            if($deal->status == DealStatusEnum::Confirmed->value)
            {
                $this->WonCelebrate($deal,$deal->employee->email);
                if($deal->employee->manager_id)
                {
                    $this->WonCelebrate($deal,$deal->employee->manager->email);
                }
                $this->CheckTargetAchieved($deal->employee);
            }
        }
        return $deal;
    }
    
    public function CheckTargetAchieved($employee)
    {
        
        $today = date('Y-m-d');
        $month = date('n');
        $year = date('Y');
        $quarter = ceil($month / 3);
        $startMonth = ($quarter - 1) * 3 + 1;
        $startOfQuarter = date('Y-m-d', strtotime("$year-$startMonth-01"));
        $endMonth = $startMonth + 2;
        $endOfQuarter = date('Y-m-t', strtotime("$year-$endMonth-01"));
        $typeStatus = DealStatusEnum::Payment_Received->value;
        
        $employees = $this->userService->get(['roles'=> UserRoleEnum::employees()]);
        
        
        $target = $this->targetService->get(['employee_id'=>$employee->id,'date_from'=>$startOfQuarter,'date_to'=>$endOfQuarter,'sum'=>'target']);
        $achieved = $this->get(['employee_id'=>$employee->id,'date_from'=>$startOfQuarter,'date_to'=>$endOfQuarter,'typeStatus'=>$typeStatus,'sum'=>'amount']);
        if($achieved >= $target && $target != 0)
        {
            $this->userService->TargetAchieved($employee);
        }
        
    }
    
    public function WonCelebrate($deal,$email)
    {
        SendMailJob::dispatch
        (
            $email,
            WonCelebrateMail::class,
            $this->veiwDirectoryMail.'won_celebrate',
            'Deal Won — Congratulations!',
            $deal,
        );
    }
    
    public function ChangeStatus($deal)
    {
        SendMailJob::dispatch
        (
            $deal->employee->email,
            ChangeStatusMail::class,
            $this->veiwDirectoryMail.'status_change',
            'Deal Status Updated — '.($deal->currentDescription->title ?? ''),
            $deal,
        );
    }

    public function confirmedDeal($deal_id)
    {
        return $this->dealRepository->confirmedDeal($deal_id);
    }
    
    public function sendReminder($deal)
    {
            SendMailJob::dispatch
            (
                $deal->employee->email,
                DeadlineReminderMail::class,
                $this->veiwDirectoryMail.'deadline_reminder',
                'Upcoming Deadline Reminder',
                $deal,
            );
    }

    public function updateLock($id)
    {
        $deal = $this->checkItem($id);
        $this->update(['lock'=>($deal->lock?0:1)],$id);
    }
    

    public function destroy(int $id): void
    {
        $deal = $this->checkItem($id);
        if ($deal)
        {
            $this->dealRepository->destroy($deal);
        }
        else
        {
            $deal = $this->getItemTrashed($id);
            $this->dealRepository->restore($deal);
        }
    }
    public function destroyAll(array $request): void
    {
        if ($request['status'] == 1)
        {
            $this->dealRepository->destroyAll($request['ids']);
        }
        else
        {
            $this->dealRepository->restoreAll($request['ids']);
        }
    }
}
