<?php

namespace App\Repositories;

use Carbon\Carbon;
use App\Models\ScheduledTask;
use App\Models\ScheduledTaskGroup;
use Illuminate\Support\Facades\DB;
use App\Models\ScheduledTaskResource;
use App\Services\ScheduledReportService;

class ScheduledTaskRepository
{
    public function store($request)
    {

        DB::beginTransaction();
        $request = array_merge($request, $this->getSendingTime($request));
        try {
            $task = ScheduledTask::create([
                'title'               => $request["title"],
                'begin_date'          => $request["begin_date"],
                'end_date'            => $request["end_date"],
                'frequency'           => $request["frequency"],
                'sending_time'        => $request['sending_time'],
                'sending_weekly_day'  => $request['sending_weekly_day'],
                'sending_monthly_day' => $request['sending_monthly_day'],
                'subject'             => $request["subject"],
                'body'                => $request["body"],
                'last_status'         => 'active',
                'next_sending_date'   => ScheduledReportService::caluclateNextSendingDate($request['frequency'], $request['begin_date'], $request['sending_time'], $request['sending_weekly_day'], $request['sending_monthly_day']),
                'created_by'          => auth()->user()->user_ID,
                'send_to_admins'      => isset($request['send_to_admins']) ? true : false,
                'month_last_day'      => isset($request['sending_monthly_day']) && $request['sending_monthly_day'] == "last" ? true : false
            ]);

            ScheduledTaskResource::create([
                'task_id'     => $task->id,
                'resource_id' => $request["report"]
            ]);

            if (isset($request["groups"]) && !is_null($request["groups"])) {

                foreach ($request["groups"] as $group) {
                    ScheduledTaskGroup::create([
                        'task_id'  => $task->id,
                        'group_id' => $group
                    ]);

                }

            }

            DB::commit();

        } catch (\Exception $e) {
            DB::rollback();
            throw $e;
        }

    }

    public function update($task, $request)
    {

        DB::beginTransaction();
        $request = array_merge($request, $this->getSendingTime($request));
        try {

            $nextSendingDate = $this->getUpdatedNextSendingDate(
                $task,
                $request['frequency'],
                $request['begin_date'],
                $request['end_date'],
                $request['sending_time'],
                $request['sending_weekly_day'],
                $request['sending_monthly_day']
            );

            $isSendingTimeChanged = $this->checkSendingTimeChanged(
                $task,
                $request['frequency'],
                $request['begin_date'],
                $request['end_date'],
                $request['sending_time'],
                $request['sending_weekly_day'],
                $request['sending_monthly_day']
            );

            $lastStatus = $this->getUpdatedLastStatus($task, $request['end_date']);

            $task->update([
                'title'               => $request["title"],
                'begin_date'          => $request["begin_date"],
                'end_date'            => $request["end_date"],
                'frequency'           => $request["frequency"],
                'sending_time'        => $request['sending_time'],
                'sending_weekly_day'  => $request['sending_weekly_day'],
                'sending_monthly_day' => $request['sending_monthly_day'],
                'subject'             => $request["subject"],
                'body'                => $request["body"],
                'last_status'         => $lastStatus,
                'next_sending_date'   => $nextSendingDate,
                'edited_by'           => auth()->user()->user_ID,
                'retry_count'         => !$isSendingTimeChanged ? $task->retry_count : 0,
                'recieved_users'      => !$isSendingTimeChanged ? $task->recieved_users : [],
                'send_to_admins'      => $request['send_to_admins'],
                'month_last_day'      => isset($request['sending_monthly_day']) && $request['sending_monthly_day'] == "last" ? true : false
            ]);

            ScheduledTaskResource::where('task_id', $task->id)->delete();

            ScheduledTaskResource::create([
                'task_id'     => $task->id,
                'resource_id' => $request["report"]
            ]);

            if (isset($request["groups"]) && !is_null($request["groups"])) {

                ScheduledTaskGroup::where('task_id', $task->id)->delete();

                foreach ($request["groups"] as $group) {
                    ScheduledTaskGroup::create([
                        'task_id'  => $task->id,
                        'group_id' => $group
                    ]);

                }

            }

            DB::commit();

        } catch (\Exception $e) {
            DB::rollback();
            throw $e;
        }

    }

    private function getSendingTime($request)
    {

        if ($request['frequency'] == "hourly") {
            return [
                'sending_time'        => null,
                'sending_weekly_day'  => null,
                'sending_monthly_day' => null
            ];
        } elseif ($request['frequency'] == "daily") {
            return [
                'sending_time'        => $request['sending_time'],
                'sending_weekly_day'  => null,
                'sending_monthly_day' => null
            ];
        } elseif ($request['frequency'] == "weekly") {
            return [
                'sending_weekly_day'  => $request['sending_weekly_day'],
                'sending_time'        => $request['sending_time'],
                'sending_monthly_day' => null
            ];

        } elseif ($request['frequency'] == "monthly") {
            return [
                'sending_monthly_day' => $request['sending_monthly_day'],
                'sending_time'        => $request['sending_time'],
                'sending_weekly_day'  => null
            ];
        }

    }

    private function getUpdatedNextSendingDate(
        $task,
        $frequency,
        $beginDate,
        $endDate,
        $sendingTime,
        $sendingWeeklyDay,
        $sendingMonthlyDay
    ) {
        return $this->checkSendingTimeChanged(
            $task,
            $frequency,
            $beginDate,
            $endDate,
            $sendingTime,
            $sendingWeeklyDay,
            $sendingMonthlyDay
        )
        ? ScheduledReportService::caluclateNextSendingDate(
            $frequency,
            $beginDate,
            $sendingTime,
            $sendingWeeklyDay,
            $sendingMonthlyDay
        )
        : $task->next_sending_date;
    }

    private function checkSendingTimeChanged($task, $frequency, $beginDate, $endDate, $sendingTime, $sendingWeeklyDay, $sendingMonthlyDay)
    {

        if (
            $task->frequency != $frequency || $task->begin_date != $beginDate || $task->end_date != $endDate
            || $task->sending_time != $sendingTime || $task->sending_weekly_day != $sendingWeeklyDay
            || $task->sending_monthly_day != $sendingMonthlyDay
        ) {
            return true;
        }

        return false;
    }

    private function getUpdatedLastStatus($task, $endDate)
    {
        $endDate = Carbon::parse($endDate);

        if ($task->last_status == "ended" && $endDate > now()) {
            return 'active';
        }

        return $task->last_status;

    }

}