<?php


namespace App\Services;

use App\Models\Event;
use Carbon\Carbon;

class EventPlannerService
{
    public function plan($user, array $data): array
    {
        $tz = $user->timezone;

        /*
        |--------------------------------------------------------------------------
        | 1. START
        |--------------------------------------------------------------------------
        */

        if (empty($data['start'])) {
            return $this->fail('Kein Startdatum erkannt');
        }

        $start = Carbon::parse($data['start'], $tz);

        /*
        |--------------------------------------------------------------------------
        | 2. DAUER + CONFIDENCE
        |--------------------------------------------------------------------------
        */

        $duration = max(5, $this->resolveDuration($user, $data));
        $confidence = $data['confidence'] ?? null;

        if ($confidence !== null && $confidence < 0.5) {
            return [
                'status' => 'needs_confirmation',
                'message' => 'Ich schätze ca. ' . $duration . ' Minuten. Passt das?',
                'meta' => [
                    'suggested_duration' => $duration,
                    'start' => $start->format('Y-m-d H:i'),
                ]
            ];
        }

        /*
        |--------------------------------------------------------------------------
        | 3. ALL DAY / NORMAL
        |--------------------------------------------------------------------------
        */

        $isAllDay = $data['is_all_day'] ?? false;

        if ($isAllDay) {

            $start = $start->copy()->startOfDay();

            $end = !empty($data['end'])
                ? Carbon::parse($data['end'], $tz)->endOfDay()
                : $start->copy()->endOfDay();

            $startUtc = $start->copy()->setTimezone('UTC');
            $endUtc = $end->copy()->setTimezone('UTC');

        } else {

            // Mehrtägig mit Zeiten: AI hat explizites End-Datum geliefert
            if (!empty($data['end'])) {
                $end = Carbon::parse($data['end'], $tz);
            } else {
                $end = $start->copy()->addMinutes($duration);
            }

            $startUtc = $start->copy()->setTimezone('UTC');
            $endUtc = $end->copy()->setTimezone('UTC');
        }

        /*
        |--------------------------------------------------------------------------
        | 4. KONFLIKT + FORCE LOGIK
        |--------------------------------------------------------------------------
        */

        $force = $data['force'] ?? false;

        $conflict = $this->hasConflict($user->id, $startUtc, $endUtc);

        if ($conflict && !$force) {

            $nextSlot = $this->findNextFreeSlot($user->id, $startUtc, $duration);
            $prevSlot = $this->findPreviousFreeSlot($user->id, $startUtc, $duration);

            $next = $nextSlot?->copy()->setTimezone($tz);
            $prev = $prevSlot?->copy()->setTimezone($tz);

            return [
                'status' => 'conflict',
                'message' => 'Termin überschneidet sich',
                'meta' => [
                    'start' => $start->format('Y-m-d H:i'),
                    'end' => $end->format('d.m.Y H:i'),
                    'suggestion_next' => $next?->format('Y-m-d H:i'),
                    'suggestion_prev' => $prev?->format('Y-m-d H:i'),
                    'duration' => $duration,
                ]
            ];
        }

        /*
        |--------------------------------------------------------------------------
        | 5. SAVE
        |--------------------------------------------------------------------------
        */

        if ($this->isDuplicate($user->id, $startUtc, $endUtc)) {
            return [
                'status' => 'duplicate',
                'message' => 'Termin existiert bereits',
                'meta' => []
            ];
        }

        $eventData = [
            'user_id' => $user->id,
            'title' => $data['title'] ?? 'Termin',
            'starts_at' => $startUtc,
            'ends_at' => $endUtc,
            'is_all_day' => $isAllDay,
            'exceptions' => $data['exceptions'] ?? [],
        ];

        if (!empty($data['notes'])) {
            $eventData['notes'] = $data['notes'];
        }

        if (!empty($data['color'])) {
            $eventData['color'] = $data['color'];
        }

        $event = Event::create($eventData);

        #TODO Das mich später freischalten

//        if (!$isAllDay) {
//
//            $durationToLearn = $data['duration_override'] ?? $duration;
//
//            if ($durationToLearn >= 5 && $durationToLearn <= 180) {
//
//                app(DurationLearningService::class)
//                    ->learn($user->id, $data['title'] ?? '', $durationToLearn);
//            }
//        }

        return [
            'status' => 'success',
            'message' => $force
                ? 'Termin trotz Konflikt gespeichert'
                : 'Termin erstellt',
            'meta' => [
                'title' => $event->title,
                'start' => $start->format('d.m.Y H:i'),
                'end' => $end->format('d.m.Y H:i'),
                'duration' => $duration,
            ]
        ];
    }

    /*
    |--------------------------------------------------------------------------
    | DAUER
    |--------------------------------------------------------------------------
    */

    protected function resolveDuration($user, array $data): int
    {
        #TODO Das mich später freischalten

//        $learning = app(\App\Services\DurationLearningService::class);

        // 👉 1. USER override (z.B. aus Modal)
        if (!empty($data['duration_override'])) {
            return (int) $data['duration_override'];
        }

        // 👉 2. LEARNING (immer davor!)
//        if ($learned = $learning->get($user->id, $data['title'] ?? '')) {
//            return $learned;
//        }

        // 👉 3. AI / Parser duration
        if (!empty($data['duration_minutes'])) {

            $ai = (int) $data['duration_minutes'];

            if ($ai >= 5 && $ai <= 180) {
                return $ai;
            }
        }

        // 👉 4. fallback map
        $map = [
            'reifenwechsel' => 60,
            'friseur' => 45,
            'arzt' => 30,
            'zahnarzt' => 45,
            'meeting' => 60,
            'paket' => 10,
        ];

        $title = strtolower($data['title'] ?? '');

        foreach ($map as $key => $minutes) {
            if (str_contains($title, $key)) {
                return $minutes;
            }
        }

        return 30;
    }


    /*
    |--------------------------------------------------------------------------
    | KONFLIKT
    |--------------------------------------------------------------------------
    */

    protected function hasConflict(string $userId, Carbon $start, Carbon $end): bool
    {
        // 1. Eintägige Termine: einfacher Zeitüberlapp (ganztägige ignorieren)
        $singleDayConflict = Event::where('user_id', $userId)
            ->where('is_all_day', false)
            ->whereRaw('DATE(starts_at) = DATE(ends_at)')
            ->where(function ($q) use ($start, $end) {
                $q->where('starts_at', '<', $end)
                    ->where('ends_at', '>', $start);
            })
            ->exists();

        if ($singleDayConflict) {
            return true;
        }

        // 2. Mehrtägige Termine (is_all_day oder regulär): Per-Day-Window-Projection
        return $this->hasMultiDayConflict($userId, $start, $end);
    }

    protected function hasMultiDayConflict(string $userId, Carbon $start, Carbon $end): bool
    {
        // Alle echten Mehrtagesevents deren Datumsbereich den neuen Termin überschneidet (ganztägige ignorieren)
        $candidates = Event::where('user_id', $userId)
            ->where('is_all_day', false)
            ->whereRaw('DATE(starts_at) < DATE(ends_at)')
            ->whereRaw('DATE(starts_at) <= ?', [$end->toDateString()])
            ->whereRaw('DATE(ends_at) >= ?', [$start->toDateString()])
            ->get();

        foreach ($candidates as $event) {
            // Reine ganztägige Termine ohne spezifische Zeiten überspringen (Fallback)
            if ($event->starts_at->format('H:i') === '00:00'
                && in_array($event->ends_at->format('H:i'), ['23:59', '00:00'])) {
                continue;
            }

            // Für jeden Tag des neuen Termins prüfen ob er ins Tagesfenster fällt
            $cursor = $start->copy()->startOfDay();
            $lastDay = $end->copy()->startOfDay();

            while ($cursor <= $lastDay) {
                $eventStartDay = $event->starts_at->copy()->startOfDay();
                $eventEndDay   = $event->ends_at->copy()->startOfDay();

                if ($cursor >= $eventStartDay && $cursor <= $eventEndDay) {
                    // Tages-Fenster auf diesen konkreten Tag projizieren
                    $windowStart = $cursor->copy()
                        ->setHour($event->starts_at->hour)
                        ->setMinute($event->starts_at->minute)
                        ->setSecond(0);

                    $windowEnd = $cursor->copy()
                        ->setHour($event->ends_at->hour)
                        ->setMinute($event->ends_at->minute)
                        ->setSecond(0);

                    // Anteil des neuen Termins an diesem Tag
                    $segStart = $start->copy()->max($cursor->copy()->startOfDay());
                    $segEnd   = $end->copy()->min($cursor->copy()->endOfDay());

                    if ($segStart < $windowEnd && $segEnd > $windowStart) {
                        return true;
                    }
                }

                $cursor->addDay();
            }
        }

        return false;
    }

    /*
    |--------------------------------------------------------------------------
    | SLOT FINDEN
    |--------------------------------------------------------------------------
    */

    protected function getBlockingEvent(string $userId, Carbon $start, Carbon $end): ?Event
    {
        // 1. Eintägige Termine: einfacher Zeitüberlapp
        $single = Event::where('user_id', $userId)
            ->whereRaw('DATE(starts_at) = DATE(ends_at)')
            ->where(function ($q) use ($start, $end) {
                $q->where('starts_at', '<', $end)
                    ->where('ends_at', '>', $start);
            })
            ->orderBy('ends_at')
            ->first();

        if ($single) {
            return $single;
        }

        // 2. Mehrtägige Termine: Per-Day-Window — blockierendes Tagesfenster zurückgeben
        $candidates = Event::where('user_id', $userId)
            ->whereRaw('DATE(starts_at) < DATE(ends_at)')
            ->whereRaw('DATE(starts_at) <= ?', [$end->toDateString()])
            ->whereRaw('DATE(ends_at) >= ?', [$start->toDateString()])
            ->get();

        foreach ($candidates as $event) {
            if ($event->starts_at->format('H:i') === '00:00'
                && in_array($event->ends_at->format('H:i'), ['23:59', '00:00'])) {
                continue;
            }

            $cursor = $start->copy()->startOfDay();
            $lastDay = $end->copy()->startOfDay();

            while ($cursor <= $lastDay) {
                $eventStartDay = $event->starts_at->copy()->startOfDay();
                $eventEndDay   = $event->ends_at->copy()->startOfDay();

                if ($cursor >= $eventStartDay && $cursor <= $eventEndDay) {
                    $windowStart = $cursor->copy()
                        ->setHour($event->starts_at->hour)
                        ->setMinute($event->starts_at->minute)
                        ->setSecond(0);

                    $windowEnd = $cursor->copy()
                        ->setHour($event->ends_at->hour)
                        ->setMinute($event->ends_at->minute)
                        ->setSecond(0);

                    $segStart = $start->copy()->max($cursor->copy()->startOfDay());
                    $segEnd   = $end->copy()->min($cursor->copy()->endOfDay());

                    if ($segStart < $windowEnd && $segEnd > $windowStart) {
                        // starts_at = Fenster-Start, ends_at = Fenster-Ende für diesen Tag
                        $event->starts_at = $windowStart;
                        $event->ends_at   = $windowEnd;
                        return $event;
                    }
                }

                $cursor->addDay();
            }
        }

        return null;
    }

    protected function findPreviousFreeSlot(string $userId, Carbon $start, int $duration): ?Carbon
    {
        $cursor = $start->copy();

        $limit = 0;

        while ($limit < 50) {

            $candidateStart = $cursor->copy()->subMinutes($duration);
            $candidateEnd   = $cursor;

            $blocking = $this->getBlockingEvent($userId, $candidateStart, $candidateEnd);

            if (!$blocking) {
                return $candidateStart;
            }

            if (!$blocking->starts_at) {
                return $candidateStart;
            }

            // 👉 nach hinten springen
            $cursor = $blocking->starts_at->copy();

            $limit++;
        }

        return null;
    }

    protected function findNextFreeSlot(string $userId, Carbon $start, int $duration): ?Carbon
    {
        $cursor = $start->copy();

        $limit = 0;

        while ($limit < 50) {

            $end = $cursor->copy()->addMinutes($duration);

            $blocking = $this->getBlockingEvent($userId, $cursor, $end);

            if (!$blocking) {
                return $cursor;
            }

            if (!$blocking->ends_at) {
                return $cursor;
            }

            $cursor = $blocking->ends_at->copy();

            $limit++;
        }

        return null;
    }

    protected function fail(string $message): array
    {
        return [
            'status' => 'failed',
            'message' => $message,
            'meta' => []
        ];
    }

    protected function isDuplicate(string $userId, Carbon $start, Carbon $end): bool
    {
        return Event::where('user_id', $userId)
            ->where('is_all_day', false)
            ->where('starts_at', $start)
            ->where('ends_at', $end)
            ->exists();
    }
}



//    protected function findNextFreeSlot(string $userId, Carbon $start, int $duration): ?Carbon
//    {
//        $cursor = $start->copy();
//
//        for ($i = 0; $i < 20; $i++) {
//
//            $end = $cursor->copy()->addMinutes($duration);
//
//            if (!$this->hasConflict($userId, $cursor, $end)) {
//                return $cursor;
//            }
//
//            $cursor->addMinutes(15);
//        }
//
//        return null;
//    }

//
//
//namespace App\Services;
//
//use App\Models\Event;
//use Carbon\Carbon;
//
//class EventPlannerService
//{
//    public function plan($user, array $data): array
//    {
//        $tz = $user->timezone;
//
//        /*
//        |--------------------------------------------------------------------------
//        | 1. START
//        |--------------------------------------------------------------------------
//        */
//
//        if (empty($data['start'])) {
//            return $this->fail('Kein Startdatum erkannt');
//        }
//
//        $start = Carbon::parse($data['start'], $tz);
//
//        /*
//        |--------------------------------------------------------------------------
//        | 2. DAUER + CONFIDENCE
//        |--------------------------------------------------------------------------
//        */
//
//        $duration = max(5, $this->resolveDuration($data));
//        $confidence = $data['confidence'] ?? null;
//
//        if ($confidence !== null && $confidence < 0.5) {
//            return [
//                'status' => 'needs_confirmation',
//                'message' => 'Ich schätze ca. ' . $duration . ' Minuten. Passt das?',
//                'meta' => [
//                    'suggested_duration' => $duration,
//                    'start' => $start->format('Y-m-d H:i'),
//                ]
//            ];
//        }
//
//        /*
//        |--------------------------------------------------------------------------
//        | 3. ALL DAY / NORMAL
//        |--------------------------------------------------------------------------
//        */
//
//        $isAllDay = $data['is_all_day'] ?? false;
//
//        if ($isAllDay) {
//            $start->setTime(0, 0);
//            $end = $start->copy()->endOfDay();
//        } else {
//            $end = $start->copy()->addMinutes($duration);
//        }
//
//        /*
//        |--------------------------------------------------------------------------
//        | 4. KONFLIKT
//        |--------------------------------------------------------------------------
//        */
//
//        $startUtc = $start->copy()->setTimezone('UTC');
//        $endUtc   = $end->copy()->setTimezone('UTC');
//
//        $conflict = $this->hasConflict($user->id, $startUtc, $endUtc);
//
//        if ($conflict) {
//
//            $nextSlot = $this->findNextFreeSlot($user->id, $startUtc, $duration);
//
//            return [
//                'status' => 'conflict',
//                'message' => 'Termin überschneidet sich',
//                'suggestion' => $nextSlot
//                    ? $nextSlot->format('d.m.Y H:i')
//                    : null,
//                'meta' => [
//                    'start' => $start->toDateTimeString(),
//                    'end' => $end->toDateTimeString(),
//                ]
//            ];
//        }
//
//        /*
//        |--------------------------------------------------------------------------
//        | 5. SAVE
//        |--------------------------------------------------------------------------
//        */
//
//        $event = Event::create([
//            'user_id' => $user->id,
//            'title' => $data['title'] ?? 'Termin',
//            'starts_at' => $start->copy()->setTimezone('UTC'),
//            'ends_at' => $end->copy()->setTimezone('UTC'),
//            'is_all_day' => $isAllDay,
//        ]);
//
//        return [
//            'status' => 'success',
//            'message' => 'Termin erstellt',
//            'meta' => [
//                'title' => $event->title,
//                'start' => $start->format('d.m.Y H:i'),
//                'end' => $end->format('d.m.Y H:i'),
//                'duration' => $duration,
//            ]
//        ];
//    }
//
//    /*
//    |--------------------------------------------------------------------------
//    | DAUER
//    |--------------------------------------------------------------------------
//    */
//
//    protected function resolveDuration(array $data): int
//    {
//        if (!empty($data['duration_minutes'])) {
//            return (int)$data['duration_minutes'];
//        }
//
//        $map = [
//            'reifenwechsel' => 60,
//            'friseur' => 45,
//            'arzt' => 30,
//            'zahnarzt' => 45,
//            'meeting' => 60,
//        ];
//
//        $title = strtolower($data['title'] ?? '');
//
//        foreach ($map as $key => $minutes) {
//            if (str_contains($title, $key)) {
//                return $minutes;
//            }
//        }
//
//        if (!empty($data['ai_duration'])) {
//            return (int)$data['ai_duration'];
//        }
//
//        return 60;
//    }
//
//    /*
//    |--------------------------------------------------------------------------
//    | KONFLIKT
//    |--------------------------------------------------------------------------
//    */
//
//    protected function hasConflict(string $userId, Carbon $start, Carbon $end): bool
//    {
//        return Event::where('user_id', $userId)
//            ->where(function ($q) use ($start, $end) {
//                $q->whereBetween('starts_at', [$start, $end])
//                    ->orWhereBetween('ends_at', [$start, $end])
//                    ->orWhere(function ($q) use ($start, $end) {
//                        $q->where('starts_at', '<=', $start)
//                            ->where('ends_at', '>=', $end);
//                    });
//            })
//            ->exists();
//    }
//
//    /*
//    |--------------------------------------------------------------------------
//    | SLOT FINDEN
//    |--------------------------------------------------------------------------
//    */
//
//    protected function findNextFreeSlot(string $userId, Carbon $start, int $duration): ?Carbon
//    {
//        $cursor = $start->copy();
//
//        for ($i = 0; $i < 20; $i++) {
//
//            $end = $cursor->copy()->addMinutes($duration);
//
//            if (!$this->hasConflict($userId, $cursor, $end)) {
//                return $cursor;
//            }
//
//            $cursor->addMinutes(15);
//        }
//
//        return null;
//    }
//
//    protected function fail(string $message): array
//    {
//        return [
//            'status' => 'failed',
//            'message' => $message,
//            'meta' => []
//        ];
//    }
//}

//
//namespace App\Services;
//
//use App\Models\Event;
//use Carbon\Carbon;
//
//class EventPlannerService
//{
//    public function plan($user, array $data): array
//    {
//        $tz = $user->timezone;
//
//        /*
//        |--------------------------------------------------------------------------
//        | 🔥 1. START ZEIT ERMITTELN
//        |--------------------------------------------------------------------------
//        */
//
//        if (empty($data['start'])) {
//            return $this->fail('Kein Startdatum erkannt');
//        }
//
//        $start = Carbon::parse($data['start'], $tz);
//
//        /*
//        |--------------------------------------------------------------------------
//        | 🔥 2. DAUER BESTIMMEN
//        |--------------------------------------------------------------------------
//        */
//
//        $duration = max(5, $this->resolveDuration($data));
//        $confidence = $data['confidence'] ?? null;
//
//        if ($confidence !== null && $confidence < 0.5) {
//            return [
//                'status' => 'needs_confirmation',
//                'message' => 'Ich schätze ca. ' . $duration . ' Minuten. Passt das?',
//                'meta' => [
//                    'suggested_duration' => $duration,
//                    'start' => $start->format('Y-m-d H:i'),
//                ]
//            ];
//        }
//
//        $end = $start->copy()->addMinutes($duration);
//
//        /*
//        |--------------------------------------------------------------------------
//        | 🔥 3. KONFLIKTE PRÜFEN
//        |--------------------------------------------------------------------------
//        */
//
//        $conflict = $this->hasConflict($user->id, $start, $end);
//
//        if ($conflict) {
//
//            $nextSlot = $this->findNextFreeSlot($user->id, $start, $duration);
//
//            return [
//                'status' => 'conflict',
//                'message' => 'Termin überschneidet sich',
//                'suggestion' => $nextSlot
//                    ? $nextSlot->format('d.m.Y H:i')
//                    : null,
//                'meta' => [
//                    'start' => $start,
//                    'end' => $end,
//                ]
//            ];
//        }
//
//        /*
//        |--------------------------------------------------------------------------
//        | 🔥 4. EVENT ERSTELLEN
//        |--------------------------------------------------------------------------
//        */
//
//        $isAllDay = $data['is_all_day'] ?? false;
//
//        if ($isAllDay) {
//            $start->setTime(0,0);
//            $end = $start->copy()->endOfDay();
//        }
//
//        $event = Event::create([
//            'user_id'   => $user->id,
//            'title'     => $data['title'] ?? 'Termin',
//            'starts_at' => $start->copy()->setTimezone('UTC'),
//            'ends_at'   => $end->copy()->setTimezone('UTC'),
//            'is_all_day'=> false,
//        ]);
//
//        return [
//            'status' => 'success',
//            'message' => 'Termin erstellt',
//            'meta' => [
//                'title' => $event->title,
//                'start' => $start->format('d.m.Y H:i'),
//                'end'   => $end->format('d.m.Y H:i'),
//                'duration' => $duration,
//            ]
//        ];
//    }
//
//    /*
//    |--------------------------------------------------------------------------
//    | 🔥 DAUER LOGIK
//    |--------------------------------------------------------------------------
//    */
//
//    protected function resolveDuration(array $data): int
//    {
//        // 🔥 1. Explizit übergeben
//        if (!empty($data['duration_minutes'])) {
//            return (int) $data['duration_minutes'];
//        }
//
//        // 🔥 2. Mapping (WICHTIG!)
//        $map = [
//            'reifenwechsel' => 60,
//            'friseur' => 45,
//            'arzt' => 30,
//            'zahnarzt' => 45,
//            'meeting' => 60,
//        ];
//
//        $title = strtolower($data['title'] ?? '');
//
//        foreach ($map as $key => $minutes) {
//            if (str_contains($title, $key)) {
//                return $minutes;
//            }
//        }
//
//        // 🔥 3. AI fallback
//        if (!empty($data['ai_duration'])) {
//            return (int) $data['ai_duration'];
//        }
//
//        // 🔥 DEFAULT
//        return 60;
//    }
//
//    /*
//    |--------------------------------------------------------------------------
//    | 🔥 KONFLIKT CHECK
//    |--------------------------------------------------------------------------
//    */
//
//    protected function hasConflict(string $userId, Carbon $start, Carbon $end): bool
//    {
//        return Event::where('user_id', $userId)
//            ->where(function ($q) use ($start, $end) {
//                $q->whereBetween('starts_at', [$start, $end])
//                    ->orWhereBetween('ends_at', [$start, $end])
//                    ->orWhere(function ($q) use ($start, $end) {
//                        $q->where('starts_at', '<=', $start)
//                            ->where('ends_at', '>=', $end);
//                    });
//            })
//            ->exists();
//    }
//
//    /*
//    |--------------------------------------------------------------------------
//    | 🔥 NÄCHSTER FREIER SLOT
//    |--------------------------------------------------------------------------
//    */
//
//    protected function findNextFreeSlot(string $userId, Carbon $start, int $duration): ?Carbon
//    {
//        $cursor = $start->copy();
//
//        for ($i = 0; $i < 20; $i++) {
//
//            $end = $cursor->copy()->addMinutes($duration);
//
//            if (!$this->hasConflict($userId, $cursor, $end)) {
//                return $cursor;
//            }
//
//            $cursor->addMinutes(15);
//        }
//
//        return null;
//    }
//
//    protected function fail(string $message): array
//    {
//        return [
//            'status' => 'failed',
//            'message' => $message,
//            'meta' => []
//        ];
//    }
//}
