<?php

declare(strict_types=1);

namespace App\Controllers;

use App\Services\GroqService;
use App\Services\GroqLimitException;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Illuminate\Database\Capsule\Manager as DB;

class WorkflowController
{
    use ControllerTrait;

    public function __construct(private GroqService $groq) {}

    private function requireAdmin(Request $request, Response $response): ?Response
    {
        return $this->requireRole($request, $response, ['admin_fab', 'super_admin']);
    }

    private function wfDb(): \Illuminate\Database\Connection
    {
        return DB::connection('workflow');
    }

    // ══════════════════════════════════════
    // TODOS — M26
    // ══════════════════════════════════════

    public function todos(Request $request, Response $response): Response
    {
        $guard = $this->requireAdmin($request, $response);
        if ($guard) return $guard;

        $params   = $request->getQueryParams();
        $parentId = isset($params['parent_id']) ? (int)$params['parent_id'] : null;

        try {
            $query = $this->wfDb()->table('todos')
                ->orderBy('ordre', 'asc')
                ->orderBy('created_at', 'desc');

            if ($parentId !== null) {
                $query->where('parent_id', $parentId);
            } else {
                $query->whereNull('parent_id');
            }

            if (!empty($params['statut'])) {
                $query->where('statut', $params['statut']);
            }

            $todos = $query->get();

            // Charger les sous-tâches récursivement (2 niveaux)
            $data = $todos->map(function ($t) {
                $subs = $this->wfDb()->table('todos')
                    ->where('parent_id', $t->id)
                    ->orderBy('ordre')->get();
                return array_merge((array)$t, ['sous_taches' => $subs->toArray()]);
            })->toArray();

            return $this->success($response, $data);
        } catch (\Exception $e) {
            return $this->success($response, []);
        }
    }

    public function createTodo(Request $request, Response $response): Response
    {
        $guard = $this->requireAdmin($request, $response);
        if ($guard) return $guard;

        $body = (array)$request->getParsedBody();

        try {
            $id = $this->wfDb()->table('todos')->insertGetId([
                'titre'       => $body['titre'] ?? '',
                'description' => $body['description'] ?? null,
                'parent_id'   => $body['parent_id'] ?? null,
                'statut'      => 'ouvert',
                'deadline'    => $body['deadline'] ?? null,
                'couleur'     => $body['couleur'] ?? null,
                'ordre'       => $body['ordre'] ?? 0,
                'created_at'  => date('Y-m-d H:i:s'),
            ]);

            $this->wfDb()->table('todo_journal')->insert([
                'todo_id'    => $id,
                'action'     => 'cree',
                'note'       => null,
                'created_at' => date('Y-m-d H:i:s'),
            ]);

            return $this->success($response, ['id' => $id], 201);
        } catch (\Exception $e) {
            return $this->error($response, 'INTERNAL_ERROR', $e->getMessage(), 500);
        }
    }

    public function updateTodo(Request $request, Response $response, array $args): Response
    {
        $guard = $this->requireAdmin($request, $response);
        if ($guard) return $guard;

        $body = (array)$request->getParsedBody();
        $id   = (int)$args['id'];

        try {
            $body['updated_at'] = date('Y-m-d H:i:s');
            $this->wfDb()->table('todos')->where('id', $id)->update($body);

            $this->wfDb()->table('todo_journal')->insert([
                'todo_id'    => $id,
                'action'     => 'modifie',
                'note'       => null,
                'created_at' => date('Y-m-d H:i:s'),
            ]);

            return $this->success($response, ['id' => $id]);
        } catch (\Exception $e) {
            return $this->error($response, 'INTERNAL_ERROR', $e->getMessage(), 500);
        }
    }

    public function cocherTodo(Request $request, Response $response, array $args): Response
    {
        $guard = $this->requireAdmin($request, $response);
        if ($guard) return $guard;

        $id   = (int)$args['id'];
        $body = (array)$request->getParsedBody();

        try {
            $todo   = $this->wfDb()->table('todos')->find($id);
            $newStatut = ($todo && $todo->statut === 'fait') ? 'ouvert' : 'fait';
            $action    = $newStatut === 'fait' ? 'fait' : 'reouvert';

            $this->wfDb()->table('todos')->where('id', $id)->update([
                'statut'     => $newStatut,
                'updated_at' => date('Y-m-d H:i:s'),
            ]);

            $this->wfDb()->table('todo_journal')->insert([
                'todo_id'    => $id,
                'action'     => $action,
                'note'       => $body['note'] ?? null,
                'created_at' => date('Y-m-d H:i:s'),
            ]);

            return $this->success($response, ['id' => $id, 'statut' => $newStatut]);
        } catch (\Exception $e) {
            return $this->error($response, 'INTERNAL_ERROR', $e->getMessage(), 500);
        }
    }

    public function deleteTodo(Request $request, Response $response, array $args): Response
    {
        $guard = $this->requireAdmin($request, $response);
        if ($guard) return $guard;

        $id = (int)$args['id'];
        try {
            $this->wfDb()->table('todos')->where('id', $id)->delete();
            $this->wfDb()->table('todos')->where('parent_id', $id)->delete();
            return $this->success($response, ['message' => 'Supprimé']);
        } catch (\Exception $e) {
            return $this->error($response, 'INTERNAL_ERROR', $e->getMessage(), 500);
        }
    }

    // ══════════════════════════════════════
    // JOURNAL — M28
    // ══════════════════════════════════════

    public function journal(Request $request, Response $response): Response
    {
        $guard = $this->requireAdmin($request, $response);
        if ($guard) return $guard;

        $params = $request->getQueryParams();
        [$page, $limit, $offset] = $this->paginate($request);

        try {
            $total   = $this->wfDb()->table('journal_entries')->count();
            $entries = $this->wfDb()->table('journal_entries')
                ->orderBy('date', 'desc')
                ->skip($offset)->take($limit)->get();

            return $this->successList($response, $entries->toArray(), ['page' => $page, 'limit' => $limit, 'total' => $total]);
        } catch (\Exception $e) {
            return $this->success($response, []);
        }
    }

    public function saveJournal(Request $request, Response $response): Response
    {
        $guard = $this->requireAdmin($request, $response);
        if ($guard) return $guard;

        $body    = (array)$request->getParsedBody();
        $date    = $body['date'] ?? date('Y-m-d');
        $contenu = $body['contenu'] ?? '';
        $humeur  = $body['humeur'] ?? 'bien';

        try {
            $this->wfDb()->table('journal_entries')->updateOrInsert(
                ['date' => $date],
                [
                    'contenu'    => $contenu,
                    'humeur'     => $humeur,
                    'updated_at' => date('Y-m-d H:i:s'),
                    'created_at' => date('Y-m-d H:i:s'),
                ]
            );

            return $this->success($response, ['date' => $date, 'message' => 'Journal sauvegardé']);
        } catch (\Exception $e) {
            return $this->error($response, 'INTERNAL_ERROR', $e->getMessage(), 500);
        }
    }

    public function resumeSemaine(Request $request, Response $response): Response
    {
        $guard = $this->requireAdmin($request, $response);
        if ($guard) return $guard;

        try {
            $entries = $this->wfDb()->table('journal_entries')
                ->where('date', '>=', date('Y-m-d', strtotime('-7 days')))
                ->orderBy('date', 'desc')
                ->get()
                ->toArray();

            if (empty($entries)) {
                return $this->success($response, ['resume' => 'Aucune entrée cette semaine.']);
            }

            try {
                $resume = $this->groq->resumeSemaine(array_map(fn($e) => (array)$e, $entries));
                return $this->success($response, ['resume' => $resume]);
            } catch (GroqLimitException $e) {
                return $this->success($response, ['resume' => 'IA indisponible — ' . $e->getMessage()]);
            }
        } catch (\Exception $e) {
            return $this->error($response, 'INTERNAL_ERROR', $e->getMessage(), 500);
        }
    }

    // ══════════════════════════════════════
    // ASSISTANT IA — M29
    // ══════════════════════════════════════

    public function assistantHistorique(Request $request, Response $response): Response
    {
        $guard = $this->requireAdmin($request, $response);
        if ($guard) return $guard;

        try {
            $history = $this->wfDb()->table('assistant_history')
                ->orderBy('created_at', 'desc')
                ->limit(20)
                ->get()
                ->reverse()
                ->values();

            return $this->success($response, $history->toArray());
        } catch (\Exception $e) {
            return $this->success($response, []);
        }
    }

    public function assistantChat(Request $request, Response $response): Response
    {
        $guard = $this->requireAdmin($request, $response);
        if ($guard) return $guard;

        $user    = $this->getAuthUser($request);
        $body    = (array)$request->getParsedBody();
        $message = trim($body['message'] ?? '');

        if (!$message) return $this->error($response, 'VALIDATION_ERROR', 'Message vide', 400);

        try {
            // Récupérer l'historique
            $history = $this->wfDb()->table('assistant_history')
                ->orderBy('created_at', 'desc')
                ->limit(10)
                ->get()
                ->reverse()
                ->values()
                ->toArray();

            // Construire le contexte
            $context = $this->buildAssistantContext();

            // Appel Groq
            try {
                $reply = $this->groq->assistantChat($message, array_map(fn($h) => (array)$h, $history), $context);
            } catch (GroqLimitException $e) {
                $reply = 'Je suis temporairement indisponible (limite quotidienne atteinte). Réessayez demain.';
            }

            // Sauvegarder échange
            $this->wfDb()->table('assistant_history')->insert([
                'user_id'    => $user->id,
                'role'       => 'user',
                'message'    => $message,
                'created_at' => date('Y-m-d H:i:s'),
            ]);
            $this->wfDb()->table('assistant_history')->insert([
                'user_id'    => $user->id,
                'role'       => 'assistant',
                'message'    => $reply,
                'created_at' => date('Y-m-d H:i:s'),
            ]);

            return $this->success($response, ['reply' => $reply]);
        } catch (\Exception $e) {
            return $this->error($response, 'INTERNAL_ERROR', $e->getMessage(), 500);
        }
    }

    public function clearHistorique(Request $request, Response $response): Response
    {
        $guard = $this->requireAdmin($request, $response);
        if ($guard) return $guard;

        try {
            $this->wfDb()->table('assistant_history')->truncate();
            return $this->success($response, ['message' => 'Historique effacé']);
        } catch (\Exception $e) {
            return $this->error($response, 'INTERNAL_ERROR', $e->getMessage(), 500);
        }
    }

    private function buildAssistantContext(): array
    {
        $context = [];

        // Tâches ouvertes avec deadline imminente
        try {
            $context['taches_urgentes'] = $this->wfDb()->table('todos')
                ->where('statut', '!=', 'fait')
                ->where('deadline', '<=', date('Y-m-d', strtotime('+7 days')))
                ->orderBy('deadline')
                ->limit(5)
                ->get()
                ->map(fn($t) => ['titre' => $t->titre, 'deadline' => $t->deadline])
                ->toArray();
        } catch (\Exception $e) {
            $context['taches_urgentes'] = [];
        }

        // KPIs du jour
        try {
            $context['kpis'] = [
                'commandes_en_attente' => DB::table('commandes')->where('statut', 'importee')->count(),
                'lots_en_cours'        => DB::table('lots')->where('statut', 'en_gravure')->count(),
                'chronos_aujourd_hui'  => DB::table('chronos')->whereDate('created_at', date('Y-m-d'))->count(),
            ];
        } catch (\Exception $e) {
            $context['kpis'] = [];
        }

        // Dernières entrées journal
        try {
            $context['journal_recent'] = $this->wfDb()->table('journal_entries')
                ->where('date', '>=', date('Y-m-d', strtotime('-7 days')))
                ->orderBy('date', 'desc')
                ->limit(3)
                ->get()
                ->map(fn($e) => ['date' => $e->date, 'humeur' => $e->humeur])
                ->toArray();
        } catch (\Exception $e) {
            $context['journal_recent'] = [];
        }

        return $context;
    }

    // ══════════════════════════════════════
    // CALENDRIER — M27
    // ══════════════════════════════════════

    public function calendrier(Request $request, Response $response): Response
    {
        $guard = $this->requireAdmin($request, $response);
        if ($guard) return $guard;

        $params = $request->getQueryParams();
        $debut  = $params['debut'] ?? date('Y-m-01');
        $fin    = $params['fin']   ?? date('Y-m-t');

        $events = [];

        // Tâches avec deadline
        try {
            $todos = $this->wfDb()->table('todos')
                ->whereNotNull('deadline')
                ->whereBetween('deadline', [$debut, $fin . ' 23:59:59'])
                ->where('statut', '!=', 'fait')
                ->get();

            foreach ($todos as $t) {
                $events[] = [
                    'type'   => 'todo',
                    'date'   => $t->deadline,
                    'titre'  => $t->titre,
                    'couleur'=> '#FF4F4F',
                    'id'     => $t->id,
                ];
            }
        } catch (\Exception $e) {}

        // Lots en gravure
        try {
            $lots = DB::table('lots')
                ->join('produits', 'produits.id', '=', 'lots.produit_id')
                ->whereIn('lots.statut', ['en_gravure', 'genere'])
                ->whereBetween('lots.created_at', [$debut, $fin . ' 23:59:59'])
                ->select(['lots.id', 'lots.created_at', 'lots.statut', 'produits.nom'])
                ->get();

            foreach ($lots as $l) {
                $events[] = [
                    'type'   => 'lot',
                    'date'   => $l->created_at,
                    'titre'  => 'Lot ' . $l->nom . ' — ' . $l->statut,
                    'couleur'=> '#F0B429',
                    'id'     => $l->id,
                ];
            }
        } catch (\Exception $e) {}

        // Expéditions prévues
        try {
            $expeditions = DB::table('commandes')
                ->whereNotNull('date_expedition')
                ->whereBetween('date_expedition', [$debut, $fin . ' 23:59:59'])
                ->select(['id', 'date_expedition', 'presta_order_ref'])
                ->get();

            foreach ($expeditions as $e) {
                $events[] = [
                    'type'   => 'expedition',
                    'date'   => $e->date_expedition,
                    'titre'  => 'Expédition ' . $e->presta_order_ref,
                    'couleur'=> '#3ECF8E',
                    'id'     => $e->id,
                ];
            }
        } catch (\Exception $e) {}

        // Événements manuels
        try {
            $manuels = $this->wfDb()->table('calendrier_events')
                ->whereBetween('date_debut', [$debut, $fin . ' 23:59:59'])
                ->get();

            foreach ($manuels as $m) {
                $events[] = [
                    'type'       => 'manuel',
                    'date'       => $m->date_debut,
                    'date_fin'   => $m->date_fin ?? null,
                    'titre'      => $m->titre,
                    'couleur'    => $m->couleur ?? '#7C5CBF',
                    'id'         => $m->id,
                    'recurrence' => $m->recurrence ?? null,
                ];
            }
        } catch (\Exception $e) {}

        // Trier par date
        usort($events, fn($a, $b) => strtotime($a['date']) - strtotime($b['date']));

        return $this->success($response, $events);
    }

    public function createEvent(Request $request, Response $response): Response
    {
        $guard = $this->requireAdmin($request, $response);
        if ($guard) return $guard;

        $body = (array)$request->getParsedBody();

        try {
            $id = $this->wfDb()->table('calendrier_events')->insertGetId([
                'titre'      => $body['titre'] ?? '',
                'date_debut' => $body['date_debut'] ?? date('Y-m-d H:i:s'),
                'date_fin'   => $body['date_fin'] ?? null,
                'couleur'    => $body['couleur'] ?? '#7C5CBF',
                'recurrence' => $body['recurrence'] ?? null,
                'notes'      => $body['notes'] ?? null,
                'created_at' => date('Y-m-d H:i:s'),
            ]);

            return $this->success($response, ['id' => $id], 201);
        } catch (\Exception $e) {
            return $this->error($response, 'INTERNAL_ERROR', $e->getMessage(), 500);
        }
    }

    public function updateEvent(Request $request, Response $response, array $args): Response
    {
        $guard = $this->requireAdmin($request, $response);
        if ($guard) return $guard;

        $body = (array)$request->getParsedBody();
        $id   = (int)$args['id'];

        try {
            $body['updated_at'] = date('Y-m-d H:i:s');
            $this->wfDb()->table('calendrier_events')->where('id', $id)->update($body);
            return $this->success($response, ['id' => $id]);
        } catch (\Exception $e) {
            return $this->error($response, 'INTERNAL_ERROR', $e->getMessage(), 500);
        }
    }

    public function deleteEvent(Request $request, Response $response, array $args): Response
    {
        $guard = $this->requireAdmin($request, $response);
        if ($guard) return $guard;

        try {
            $this->wfDb()->table('calendrier_events')->where('id', (int)$args['id'])->delete();
            return $this->success($response, ['message' => 'Événement supprimé']);
        } catch (\Exception $e) {
            return $this->error($response, 'INTERNAL_ERROR', $e->getMessage(), 500);
        }
    }

    // ══════════════════════════════════════
    // CONFIG
    // ══════════════════════════════════════

    public function config(Request $request, Response $response): Response
    {
        $guard = $this->requireAdmin($request, $response);
        if ($guard) return $guard;

        $groqUsage = $this->groq->getUsageToday();

        // Clé Groq masquée
        $groqKey = $_ENV['GROQ_API_KEY'] ?? '';
        $groqKeyMasked = $groqKey ? substr($groqKey, 0, 8) . '...' : null;

        return $this->success($response, [
            'groq_api_key'    => $groqKeyMasked,
            'groq_daily_limit'=> $groqUsage['limite'],
            'groq_usage_today'=> $groqUsage,
            'maintenance_mode'=> ($_ENV['MAINTENANCE_MODE'] ?? 'false') === 'true',
        ]);
    }
}
