<?php

namespace App\Http\Controllers;

use App\Helpers\TimeLine;
use App\Models\Appointment;
use App\Models\BDTDevice;
use App\Models\CareMonth;
use App\Models\Client;
use App\Models\ClientInfoLine;
use App\Models\Facility;
use App\Models\NoteTemplate;
use App\Models\Pro;
use App\Models\ProGeneralAvailability;
use App\Models\ProSpecificAvailability;
use App\Models\ProSpecificUnavailability;
use App\Models\SectionTemplate;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\File;

class AppointmentController extends Controller
{
    public function events(Request $request)
    {
        if(empty($request->get('proIds'))) {
            $proIds = [];
        }
        else {
            $proIds = explode(',', $request->get('proIds'));
        }

        $start = $request->get('start');
        $end = $request->get('end');
        $clientId = $request->get('clientId');
        $timeZone = $request->get('timeZone');

        // get appointments
        $appointments = Appointment
            ::where('start_time', '>=', $start)
            ->where('start_time', '<=', $end);

        if(count($proIds)) {
            $appointments = $appointments
                ->where(function ($query) use ($proIds, $clientId) {
                    $query
                        ->whereIn('pro_id', $proIds)
                        ->orWhere('client_id', '=', $clientId);
                });
        }

        $appointments = $appointments->get();

        $events = [];
        foreach ($appointments as $appointment) {

            // default - as used from patient calendar
            $title = ($appointment->client->id != $clientId ? '* ' : '') . $appointment->pro->displayName() .
                " (" . strtolower($appointment->status) . ")";

            if($clientId == "-1") {

                $shortStatus = '';
                switch($appointment->status) {
                    case 'CREATED':
                        $shortStatus = 'new';
                        break;
                    case 'CONFIRMED':
                        $shortStatus = 'conf';
                        break;
                    case 'CANCELLED':
                        $shortStatus = 'canc';
                        break;
                    case 'COMPLETED':
                        $shortStatus = 'done';
                        break;
                    case 'ABANDONED':
                        $shortStatus = 'aban';
                        break;
                    case 'REJECTED':
                        $shortStatus = 'rej';
                        break;
                }

                if(count($proIds) === 1) {
                    $title = "($shortStatus) " . $appointment->client->displayName();
                }
                else {
                    $title = '[' . $appointment->pro->initials()  . '] ' .
                        "($shortStatus) " . $appointment->client->displayName();
                }
            }

            $events[] = [
                "type" => "appointment",
                "title" => $title,
                "_title" => $appointment->title,
                "description" => $appointment->description,
                "clientName" => $appointment->client->displayName(),
                "appointmentUid" => $appointment->uid,
                "clientUid" => $appointment->client->uid,
                "proId" => $appointment->pro->id,
                "proUid" => $appointment->pro->uid,
                "proName" => $appointment->pro->displayName(),
                "start" => convertToTimezone($appointment->start_time, $timeZone),
                "end" => convertToTimezone($appointment->end_time, $timeZone),
                "clientOnly" => !in_array($appointment->pro->id, $proIds),
                "otherClient" => ($appointment->client->id != $clientId),
                "status" => $appointment->status,
                "editable" => true
            ];
        }

        if(count($proIds)) {

            // get availability
            $genAvail = ProGeneralAvailability
                ::where('is_cancelled', false)
                ->whereIn('pro_id', $proIds)
                ->get();
            $specAvail = ProSpecificAvailability
                ::where('is_cancelled', false)
                ->whereIn('pro_id', $proIds)
                ->where(function ($query) use ($start, $end) {
                    $query
                        ->where(function ($query2) use ($start, $end) {
                            $query2
                                ->where('start_time', '>=', $start)
                                ->where('start_time', '<=', $end);
                        })
                        ->orWhere(function ($query2) use ($start, $end) {
                            $query2
                                ->where('end_time', '>=', $start)
                                ->where('end_time', '<=', $end);
                        });
                })
                ->get();
            $specUnavail = ProSpecificUnavailability
                ::where('is_cancelled', false)
                ->whereIn('pro_id', $proIds)
                ->where(function ($query) use ($start, $end) {
                    $query
                        ->where(function ($query2) use ($start, $end) {
                            $query2
                                ->where('start_time', '>=', $start)
                                ->where('start_time', '<=', $end);
                        })
                        ->orWhere(function ($query2) use ($start, $end) {
                            $query2
                                ->where('end_time', '>=', $start)
                                ->where('end_time', '<=', $end);
                        });
                })
                ->get();

            // logic
            // 1. enumerate days between start and end (inclusive)
            // 2. for each pro
            // 3. calculate pairs of start-end of availability

            // 1. enumerate days between start and end (inclusive)
            $phpTZ = appTZtoPHPTZ($timeZone);
            $phpTZObject = new \DateTimeZone($phpTZ);
            $startDate = new \DateTime($start, $phpTZObject);
            $endDate = new \DateTime($end, $phpTZObject);
            $endDate->setTime(23, 59, 59);
            $period = new \DatePeriod($startDate, \DateInterval::createFromDateString('1 day'), $endDate);
            $days = [];
            foreach ($period as $day) {
                $days[] = [
                    "day" => strtoupper($day->format("l")), // SUNDAY, etc.
                    "date" => $day->format("Y-m-d"), // 2020-10-04, etc.
                ];
            }

            foreach ($proIds as $proId) {

                $proTimeLine = new TimeLine($startDate, $endDate);

                $pro = Pro::where('id', $proId)->first();

                $proGenAvail = $genAvail->filter(function ($record) use ($proId) {
                    return $record->pro_id == $proId;
                });

                // if no gen avail, assume mon to fri, 9 to 7
                /*if (!count($proGenAvail)) {
                    $dayNames = ['MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY', 'FRIDAY'];
                    foreach ($dayNames as $dayName) {
                        $item = new \stdClass();
                        $item->day_of_week = $dayName;
                        $item->timezone = $timeZone;
                        $item->start_time = '09:00:00';
                        $item->end_time = '18:00:00';
                        $proGenAvail->push($item);
                    }
                }*/

                $proSpecAvail = $specAvail->filter(function ($record) use ($proId) {
                    return $record->pro_id == $proId;
                });

                $proSpecUnavail = $specUnavail->filter(function ($record) use ($proId) {
                    return $record->pro_id == $proId;
                });

                // general availability
                foreach ($days as $day) {

                    $proGenAvailForTheDay = $proGenAvail->filter(function ($record) use ($day) {
                        return $record->day_of_week === $day["day"];
                    });
                    foreach ($proGenAvailForTheDay as $ga) {

                        $gaStart = new \DateTime($day["date"], new \DateTimeZone(appTZtoPHPTZ($ga->timezone)));
                        $parts = explode(":", $ga->start_time);
                        $gaStart->setTime(intval($parts[0]), intval($parts[1]), intval($parts[2]));
                        $gaStart->setTimezone($phpTZObject);

                        $gaEnd = new \DateTime($day["date"], new \DateTimeZone(appTZtoPHPTZ($ga->timezone)));
                        $parts = explode(":", $ga->end_time);
                        $gaEnd->setTime(intval($parts[0]), intval($parts[1]), intval($parts[2]));
                        $gaEnd->setTimezone($phpTZObject);

                        $proTimeLine->addAvailability($gaStart, $gaEnd);
                    }

                }

                // specific availability
                foreach ($proSpecAvail as $sa) {
                    $saStart = new \DateTime($sa->start_time, new \DateTimeZone(appTZtoPHPTZ($sa->timezone)));
                    $saStart->setTimezone($phpTZObject);
                    $saEnd = new \DateTime($sa->end_time, new \DateTimeZone(appTZtoPHPTZ($sa->timezone)));
                    $saEnd->setTimezone($phpTZObject);
                    $proTimeLine->addAvailability($saStart, $saEnd);
                }

                // specific unavailability
                foreach ($proSpecUnavail as $sua) {
                    $suaStart = new \DateTime($sua->start_time, new \DateTimeZone(appTZtoPHPTZ($sua->timezone)));
                    $suaStart->setTimezone($phpTZObject);
                    $suaEnd = new \DateTime($sua->end_time, new \DateTimeZone(appTZtoPHPTZ($sua->timezone)));
                    $suaEnd->setTimezone($phpTZObject);
                    $proTimeLine->removeAvailability($suaStart, $suaEnd);
                }

                // make already booked slots unavailable
                $proAppointments = $appointments->filter(function ($record) use ($proId) {
                    return $record->pro_id == $proId && !in_array($record->status, ['CANCELLED', 'COMPLETED', 'ABANDONED']);
                });
                foreach ($proAppointments as $appointment) {
                    if ($appointment->start_time && $appointment->end_time) {
                        $appStart = convertToTimezone($appointment->start_time, $timeZone, 'UTC', true);
                        $appEnd = convertToTimezone($appointment->end_time, $timeZone, 'UTC', true);
                        $proTimeLine->removeAvailability($appStart, $appEnd);
                    }
                }

                foreach ($proTimeLine->available as $item) {

                    $eStart = new \DateTime('@' . $item->start);
                    $eStart->setTimezone($phpTZObject);

                    $eEnd = new \DateTime('@' . $item->end);
                    $eEnd->setTimezone($phpTZObject);

                    $events[] = [
                        "type" => "availability",
                        "title" => $pro->displayName() . " (available)",
                        "proId" => $pro->id,
                        "proUid" => $pro->uid,
                        "start" => $eStart->format('Y-m-d H:i:s'),
                        "end" => $eEnd->format('Y-m-d H:i:s'),
                        "editable" => false
                    ];

                }

            }

        }

        return json_encode($events);
    }

    public function appointmentConfirmationHistory(Request $request, Appointment $appointment) {
        return view('app.patient.partials.appointment-confirmation-history', compact('appointment'));
    }

}
