<?php
declare(strict_types=1);

namespace App\Controller\Admin;

use Cake\Http\Exception\NotFoundException;
use Cake\Http\Response;
use Cake\ORM\TableRegistry;
use Cake\Utility\Text;
use DateTimeImmutable;

class TeachersController extends AdminAppController
{
    public function index(): void
    {
        $teachers = TableRegistry::getTableLocator()->get('Teachers');
        $rows = $teachers->find()
            ->orderBy(['is_active' => 'DESC', 'sort_order' => 'ASC', 'full_name' => 'ASC'])
            ->all();

        // Slot counts per teacher
        $slotCounts = TableRegistry::getTableLocator()->get('AvailabilitySlots')->find()
            ->select(['teacher_id', 'open' => 'COUNT(*)'])
            ->where(['is_booked' => false, 'starts_at >=' => date('Y-m-d H:i:s')])
            ->groupBy('teacher_id')
            ->all()
            ->combine('teacher_id', 'open')
            ->toArray();

        $this->set(compact('rows', 'slotCounts'));
    }

    public function add(): ?Response
    {
        $teachers = TableRegistry::getTableLocator()->get('Teachers');
        $teacher = $teachers->newEmptyEntity();

        if ($this->request->is('post')) {
            $data = $this->request->getData();
            if (empty($data['slug']) && !empty($data['full_name'])) {
                $data['slug'] = $this->uniqueSlug((string)$data['full_name']);
            }
            $data['is_active'] = !empty($data['is_active']);
            $teacher = $teachers->patchEntity($teacher, $data);
            if ($teachers->save($teacher)) {
                $this->Flash->success('Teacher added.');
                return $this->redirect(['_name' => 'admin_teacher_edit', 'id' => $teacher->id]);
            }
            $this->Flash->error('Could not save — please check the highlighted fields.');
        }

        $this->set(compact('teacher'));
        return null;
    }

    public function edit(int $id): ?Response
    {
        $teachers = TableRegistry::getTableLocator()->get('Teachers');
        $teacher = $teachers->get($id);

        if ($this->request->is(['put', 'patch', 'post'])) {
            $data = $this->request->getData();
            $data['is_active'] = !empty($data['is_active']);
            $teacher = $teachers->patchEntity($teacher, $data);
            if ($teachers->save($teacher)) {
                $this->Flash->success('Teacher updated.');
                return $this->redirect(['_name' => 'admin_teacher_edit', 'id' => $id]);
            }
            $this->Flash->error('Could not update — please check the highlighted fields.');
        }

        // Upcoming slots for this teacher
        $slots = TableRegistry::getTableLocator()->get('AvailabilitySlots')->find()
            ->where(['teacher_id' => $teacher->id, 'starts_at >=' => date('Y-m-d H:i:s')])
            ->orderBy(['starts_at' => 'ASC'])
            ->limit(120)
            ->all();

        $this->set(compact('teacher', 'slots'));
        return null;
    }

    public function deactivate(int $id): ?Response
    {
        $this->request->allowMethod(['post']);
        $teachers = TableRegistry::getTableLocator()->get('Teachers');
        $teacher = $teachers->get($id);
        $teacher->is_active = !$teacher->is_active;
        $teachers->save($teacher);
        $this->Flash->success($teacher->is_active ? 'Teacher reactivated.' : 'Teacher deactivated.');
        return $this->redirect($this->referer(['_name' => 'admin_teachers']));
    }

    public function addSlot(int $id): ?Response
    {
        $this->request->allowMethod(['post']);
        $teachers = TableRegistry::getTableLocator()->get('Teachers');
        $teacher = $teachers->get($id);

        $date = trim((string)$this->request->getData('date'));
        $time = trim((string)$this->request->getData('time'));
        $classType = trim((string)$this->request->getData('class_type', 'pottery'));
        $duration = max(30, min(360, (int)$this->request->getData('duration', 90)));

        if ($date === '' || $time === '') {
            $this->Flash->error('Please provide both a date and a time.');
            return $this->redirect(['_name' => 'admin_teacher_edit', 'id' => $id]);
        }

        try {
            $start = new DateTimeImmutable("{$date} {$time}");
        } catch (\Throwable) {
            $this->Flash->error('Invalid date or time.');
            return $this->redirect(['_name' => 'admin_teacher_edit', 'id' => $id]);
        }
        $end = $start->modify("+{$duration} minutes");

        $slots = TableRegistry::getTableLocator()->get('AvailabilitySlots');
        $slot = $slots->newEntity([
            'teacher_id' => $teacher->id,
            'starts_at' => $start->format('Y-m-d H:i:s'),
            'ends_at' => $end->format('Y-m-d H:i:s'),
            'class_type' => in_array($classType, ['pottery', 'knitting'], true) ? $classType : 'pottery',
            'capacity' => 1,
            'is_booked' => false,
        ]);
        if ($slots->save($slot)) {
            $this->Flash->success('Slot added.');
        } else {
            $this->Flash->error('Could not add slot.');
        }
        return $this->redirect(['_name' => 'admin_teacher_edit', 'id' => $id]);
    }

    public function deleteSlot(int $id, int $slotId): ?Response
    {
        $this->request->allowMethod(['post', 'delete']);
        $slots = TableRegistry::getTableLocator()->get('AvailabilitySlots');
        $slot = $slots->find()->where(['id' => $slotId, 'teacher_id' => $id])->first();
        if (!$slot) {
            throw new NotFoundException('Slot not found.');
        }
        if ($slot->is_booked) {
            $this->Flash->error('Cannot delete a slot that is already booked.');
        } else {
            $slots->delete($slot);
            $this->Flash->success('Slot deleted.');
        }
        return $this->redirect(['_name' => 'admin_teacher_edit', 'id' => $id]);
    }

    public function generateSlots(int $id): ?Response
    {
        $this->request->allowMethod(['post']);
        $teachers = TableRegistry::getTableLocator()->get('Teachers');
        $teacher = $teachers->get($id);

        $days = max(1, min(60, (int)$this->request->getData('days', 14)));
        $classType = $this->request->getData('class_type', 'pottery');
        if (!in_array($classType, ['pottery', 'knitting'], true)) {
            $classType = 'pottery';
        }
        $times = ['10:00', '13:00', '16:00'];

        $slots = TableRegistry::getTableLocator()->get('AvailabilitySlots');
        $base = new DateTimeImmutable('tomorrow');
        $created = 0;

        for ($d = 0; $d < $days; $d++) {
            $day = $base->modify("+{$d} days");
            if ($day->format('w') === '0') continue; // skip Sundays
            foreach ($times as $t) {
                $start = $day->format('Y-m-d') . ' ' . $t . ':00';
                // Skip if a slot already exists at the same time
                $exists = $slots->find()->where([
                    'teacher_id' => $teacher->id,
                    'starts_at' => $start,
                ])->count();
                if ($exists > 0) continue;

                $end = (new DateTimeImmutable($start))->modify('+90 minutes')->format('Y-m-d H:i:s');
                $entity = $slots->newEntity([
                    'teacher_id' => $teacher->id,
                    'starts_at' => $start,
                    'ends_at' => $end,
                    'class_type' => $classType,
                    'capacity' => 1,
                    'is_booked' => false,
                ]);
                if ($slots->save($entity)) {
                    $created++;
                }
            }
        }

        $this->Flash->success("Generated {$created} slots over the next {$days} days.");
        return $this->redirect(['_name' => 'admin_teacher_edit', 'id' => $id]);
    }

    private function uniqueSlug(string $name): string
    {
        $teachers = TableRegistry::getTableLocator()->get('Teachers');
        $base = Text::slug(strtolower(trim($name)), '-');
        if ($base === '') {
            $base = 'teacher';
        }
        $slug = $base;
        $i = 1;
        while ($teachers->exists(['slug' => $slug])) {
            $slug = $base . '-' . (++$i);
        }
        return $slug;
    }
}
