<?php

namespace App\Repositories;

use Carbon\Carbon;
use App\Models\Hrm\Shift\Shift;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use App\Models\Hrm\Attendance\Holiday;
use App\Models\Hrm\Attendance\Weekend;
use App\Helpers\CoreApp\Traits\DateHandler;
use App\Models\Hrm\Attendance\DutySchedule;
use App\Helpers\CoreApp\Traits\ApiReturnFormatTrait;
use App\Models\coreApp\Relationship\RelationshipTrait;

class DutyScheduleRepository
{
    use RelationshipTrait, ApiReturnFormatTrait, DateHandler;

    protected $dutySchedule;

    public function __construct(DutySchedule $dutySchedule)
    {
        $this->dutySchedule = $dutySchedule;
    }

    public function index()
    {
        $data['title'] = 'Duty Schedule';
        $data['schedules'] = DutySchedule::query()->where('company_id', getCurrentCompany())->get();
        return $data;
    }

    public function create()
    {
        $data['title'] = 'Create Duty Schedule';
        return $data;
    }

    public function show($id)
    {
        $data['title'] = 'Edit Duty Schedule';
        $data['duty_schedule'] = DutySchedule::find($id);
        return $data;
    }

    public function store($request)
    {
        if ($request->end_on_same_date == 1) {
            $end_date = date('Y-m-d');
        } else {
            $end_date = date('Y-m-d', strtotime('+1 day'));
        }

        $start_time = date('Y-m-d') . ' ' . $request->start_time . ':00';
        $end_time   = $end_date . ' ' . $request->end_time . ':00';
        $to         = Carbon::createFromFormat('Y-m-d H:s:i', $start_time);
        $from       = Carbon::createFromFormat('Y-m-d H:s:i', $end_time);

        $diffInMinutes = $to->diffInMinutes($from);

        $this->dutySchedule->create([
            "shift"            => $request->shift,
            "consider_time"    => $request->consider_time,
            "start_time"       => $request->start_time,
            "end_time"         => $request->end_time,
            "hour"             => $diffInMinutes / 60,
            "end_on_same_date" => $request->end_on_same_date,
            "status_id"        => $request->status_id,
        ]);

        return true;
    }

    public function update($request, $dutySchedule)
    {
        $startDate = now()->toDateString();
        $endDate = $request->end_on_same_date ? $startDate : now()->addDay()->toDateString();

        $startDateTime = "{$startDate} {$request->start_time}";
        $endDateTime   = "{$endDate} {$request->end_time}";

        // Use Carbon::parse (safer & more flexible)
        $start = Carbon::parse($startDateTime);
        $end   = Carbon::parse($endDateTime);

        $diffInHours = $start->diffInMinutes($end) / 60;

        $dutySchedule->update([
            'shift'            => $request->shift,
            'consider_time'    => $request->consider_time ?? 0,
            'start_time'       => $request->start_time,
            'end_time'         => $request->end_time,
            'hour'             => $diffInHours,
            'end_on_same_date' => $request->end_on_same_date,
            'status_id'        => $request->status_id,
        ]);

        return true;
    }

    public function distroy($duty_schedule_id)
    {
        try {
            $dutySchedule = $this->dutySchedule->find($duty_schedule_id);
            $dutySchedule->delete();
            return true;
        } catch (\Throwable $th) {
            Log::error($th);
        }
    }


    public function getUserToDaySchedule()
    {
        $userSchedule = $this->dutySchedule->query()
            ->where('company_id', getCurrentCompany())
            ->where('id', auth()->user()->duty_schedule_id)
            ->first();
        if ($userSchedule) {
            $user_duty_schedule = [
                'start_time' => [
                    'hour' => (int) date('H', strtotime($userSchedule->start_time)),
                    'min' => (int) date('i', strtotime($userSchedule->start_time)),
                    'sec' => (int) date('s', strtotime($userSchedule->start_time)),
                ],
                'end_time' => [
                    'hour' => (int) date('H', strtotime($userSchedule->end_time)),
                    'min' => (int) date('i', strtotime($userSchedule->end_time)),
                    'sec' => (int) date('s', strtotime($userSchedule->end_time)),
                ],
                'list_of_start_datetime' => $this->officeDaysTimeOfMonth($userSchedule->start_time, 1000000),
                'list_of_end_datetime' => $this->officeDaysTimeOfMonth($userSchedule->end_time, 2000000),
            ];
        } else {
            $user_duty_schedule = [
                'start_time' => [
                    'hour' => 0,
                    'min' => 0,
                    'sec' => 0,
                ],
                'end_time' => [
                    'hour' => 0,
                    'min' => 0,
                    'sec' => 0,
                ],
            ];
        }
        return $user_duty_schedule;
    }


    public function officeDaysTimeOfMonth($time, $number)
    {
        $thisMonthArray = [];
        $thisMonthArray = $this->getNext30Days();
        foreach ($thisMonthArray as $key => $item) {
            $day = Carbon::parse($item);
            $todayDateInSqlFormat = $day->format('Y-m-d');
            $weekEnds = Weekend::where(['company_id' => getCurrentCompany(), 'is_weekend' => 'yes'])->pluck('name')->toArray();
            $todayDateName = strtolower($day->format('l'));
            if (in_array($todayDateName, $weekEnds)) {
                //$dailyReports[] = "Weekend";
                continue;
            } else {
                $isHoliday = Holiday::where('company_id', getCurrentCompany())
                    ->where('start_date', '<=', $todayDateInSqlFormat)
                    ->where('end_date', '>=', $todayDateInSqlFormat)
                    ->select('start_date', 'end_date')
                    ->first();
                if ($isHoliday) {
                    //$dailyReports[] = "Holiday";
                    continue;
                } else {
                    $timeString = (int) date('H', strtotime($time)) . ":" . (int) date('i', strtotime($time));
                    //$dailyReports[] = $todayDateInSqlFormat." ".$timeString;
                    $unique_id = $number + ($key + 1);
                    $dailyReports[] = [
                        'id' => $unique_id,
                        'datetime' => $todayDateInSqlFormat . " " . $timeString,
                    ];
                }
            }
        }
        return $dailyReports;
    }

    //new functions
    function fields()
    {
        return [
            _trans('common.ID'),
            _trans('common.Shift'),
            _trans('common.Start Time'),
            _trans('common.End Time'),
            _trans('common.Hours'),
            _trans('attendance.Consider Time'),
            _trans('common.Status'),
            _trans('common.Action'),
        ];
    }

    function table($request)
    {
        $data = $this->dutySchedule->query()->where('company_id', getCurrentCompany())
            ->when($request->search, fn($query, $search) => $query->where('shift', 'like', "%$search%"))
            ->when($request->from && $request->to, fn($query, $search) => $query->whereBetween('created_at',  start_end_datetime($request->from, $request->to)))
            ->orderBy('created_at', 'DESC')
            ->paginate($request->limit ?? 25);

        return [
            'data' => $data->map(function ($data) {
                $action_button = '';
                if (hasPermission('schedule_update')) {
                    $action_button .= actionButton(_trans('common.Edit'), route('dutySchedule.show', $data->id), 'profile');
                }
                if (hasPermission('schedule_delete')) {
                    $action_button .= actionButton(_trans('common.Delete'), '__globalDelete(' . $data->id . ',`hrm/duty/schedule/delete/`)', 'delete');
                }
                $button = ' <div class="dropdown dropdown-action">
                             <button type="button" class="btn-dropdown" data-bs-toggle="dropdown"
                                 aria-expanded="false">
                                 <i class="fa-solid fa-ellipsis"></i>
                             </button>
                             <ul class="dropdown-menu dropdown-menu-end">
                             ' . $action_button . '
                             </ul>
                         </div>';
                return [
                    'id'            => $data->id,
                    'shift'         => $data->shift,
                    'start_time'    => showTime($data->start_time),
                    'end_time'      => showTime($data->end_time),
                    'hour'          => $data->hour,
                    'consider_time' => $data->consider_time,
                    'status'        => '<span class="badge badge-' . @$data->status->class . '">' . @$data->status->name . '</span>',
                    'action'        => $button
                ];
            }),
            'pagination' => [
                'total' => $data->total(),
                'count' => $data->count(),
                'per_page' => $data->perPage(),
                'current_page' => $data->currentPage(),
                'total_pages' => $data->lastPage(),
                'pagination_html' =>  $data->links('backend.pagination.custom')->toHtml(),
            ],
        ];
    }

    public function destroyAll($request)
    {
        try {
            if (@$request->ids) {
                $duty_schedule = $this->dutySchedule->where('company_id', auth()->user()->company_id)->whereIn('id', $request->ids)->delete();
                return $this->responseWithSuccess(_trans('message.Duty schedule delete successfully.'), $duty_schedule);
            } else {
                return $this->responseWithError(_trans('message.Duty schedule not found'), [], 400);
            }
        } catch (\Throwable $th) {
            return $this->responseWithError($th->getMessage(), [], 400);
        }
    }

    public function bulkStore($request)
    {
        try {
            DB::beginTransaction();

            $uploadFile = $request->file('file');
            $filePath   = $uploadFile->getRealPath();

            $file       = fopen($filePath, 'r');
            $firstLine  = true;
            $lineNumber = 0;

            // First, scan for duplicates in the entire file
            while ($data = fgetcsv($file)) {
                if (!$firstLine) {
                    $shift     = trim($data[1]);
                    $startTime = trim($data[2]);
                    $endTime   = trim($data[3]);

                    if (!$shift || !$startTime || !$endTime) {
                        throw new \Exception("Missing data at line numbers: $lineNumber");
                    }
                }
                $firstLine = false;
                $lineNumber++;
            }

            fseek($file, 0);
            $firstLine = true;

            while ($data = fgetcsv($file)) {
                if (!$firstLine) {
                    $shiftName     = trim($data[0]);
                    $startTime     = trim($data[1]);
                    $endTime       = trim($data[2]);
                    $considerTime  = trim($data[3]) ?? 0;
                    $endOnSameDate = trim($data[4]) ?? 1;


                    if ($endOnSameDate == 1) {
                        $endDate = date('Y-m-d');
                    } else {
                        $endDate = date('Y-m-d', strtotime('+1 day'));
                    }

                    $startTime     = date('Y-m-d') . ' ' . $startTime . ':00';
                    $endTime       = $endDate . ' ' . $endTime . ':00';
                    $to            = Carbon::createFromFormat('Y-m-d H:s:i', $startTime);
                    $from          = Carbon::createFromFormat('Y-m-d H:s:i', $endTime);
                    $diffInMinutes = $to->diffInMinutes($from);
                    $hours         = $diffInMinutes / 60;

                    DutySchedule::firstOrCreate(
                        [
                            "shift"   => $shiftName,
                            "start_time" => $startTime,
                            "end_time"   => $endTime,
                            "company_id" => userCompanies(),
                            "branch_id"  => userBranch()
                        ],
                        [
                            "hour"             => $hours,
                            "consider_time"    => $considerTime,
                            "end_on_same_date" => $endOnSameDate,
                            "status_id"        => 1,
                        ]
                    );
                }
                $firstLine = false;
            }

            DB::commit();
            return true;
        } catch (\Exception $exception) {
            DB::rollBack();
            throw $exception;
        }
    }
}
