<?php

declare(strict_types=1);

namespace App\Controllers;

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

/**
 * ChatController — Messagerie fabricants MyKollectOr®
 *
 * Architecture :
 *   • 1 conversation par entreprise (contact_id mykolluwork)
 *   • Tous les opérateurs d'un même contact_id partagent le fil
 *   • Julien (super_admin) est participant de toutes les conversations
 *   • Julien ne voit que ses wizz non répondus (vue dédiée julien-wizz.html)
 */
class ChatController
{
    use ControllerTrait;

    // ─────────────────────────────────────────────────────────
    // HELPERS PRIVÉS
    // ─────────────────────────────────────────────────────────

    /** Retrouve le contact_id (mykolluwork) via l'atelier de l'utilisateur */
    private function getContactId(object $user): ?int
    {
        if (!$user->atelier_id) return null;

        $atelier = DB::table('ateliers')
            ->where('id', $user->atelier_id)
            ->first();

        return $atelier?->contact_id ?? null;
    }

    /** Retrouve ou crée le super_admin (Julien) */
    private function getJulien(): ?object
    {
        return DB::table('users')
            ->where('email', 'julien@mykollector.com')
            ->orWhere('role', 'super_admin')
            ->orderByRaw("CASE WHEN email='julien@mykollector.com' THEN 0 ELSE 1 END")
            ->first();
    }

    /** Retrouve ou crée la conversation du contact_id */
    private function getOrCreateConversation(int $contactId, int $julienId): int
    {
        $existing = DB::table('chat_conversations')
            ->where('contact_id', $contactId)
            ->value('id');

        if ($existing) return (int)$existing;

        // Chercher le nom de l'entreprise dans mykolluwork
        $contact = null;
        try {
            $contact = DB::connection('workflow')
                ->table('contacts')
                ->where('id', $contactId)
                ->first();
        } catch (\Exception $e) { /* ignore si DB workflow indispo */ }

        $titre = $contact ? ($contact->nom ?? 'Entreprise #' . $contactId) : 'Entreprise #' . $contactId;

        $convId = DB::table('chat_conversations')->insertGetId([
            'titre'      => $titre,
            'contact_id' => $contactId,
            'created_at' => date('Y-m-d H:i:s'),
        ]);

        // Julien est toujours participant
        DB::table('chat_participants')->insert([
            'conversation_id' => $convId,
            'user_id'         => $julienId,
        ]);

        return (int)$convId;
    }

    /** Ajoute un opérateur comme participant s'il ne l'est pas déjà */
    private function ensureParticipant(int $convId, int $userId): void
    {
        $exists = DB::table('chat_participants')
            ->where('conversation_id', $convId)
            ->where('user_id', $userId)
            ->exists();

        if (!$exists) {
            DB::table('chat_participants')->insert([
                'conversation_id' => $convId,
                'user_id'         => $userId,
            ]);
        }
    }

    // ─────────────────────────────────────────────────────────
    // ROUTES OPÉRATEURS FAB
    // ─────────────────────────────────────────────────────────

    /**
     * GET /api/chat/conversations
     * Retourne la conversation de l'entreprise de l'opérateur (1 seule).
     * Julien voit toutes les conversations (pour son panneau admin).
     */
    public function conversations(Request $request, Response $response): Response
    {
        $user = $this->getAuthUser($request);
        if (!$user) return $this->error($response, 'UNAUTHORIZED', 'Non authentifié', 401);

        $isSuperAdmin = ($user->role === 'super_admin' || $user->email === 'julien@mykollector.com');

        if ($isSuperAdmin) {
            // Julien : toutes les conversations triées par activité récente
            $conversations = DB::table('chat_conversations')
                ->orderBy('updated_at', 'desc')
                ->orderBy('created_at', 'desc')
                ->get();
        } else {
            // Opérateur : uniquement la conversation de son entreprise
            $contactId = $this->getContactId($user);
            if (!$contactId) {
                return $this->success($response, []);
            }

            $conversations = DB::table('chat_conversations')
                ->where('contact_id', $contactId)
                ->get();
        }

        $data = $conversations->map(function ($conv) use ($user, $isSuperAdmin) {
            $lastMsg = DB::table('chat_messages')
                ->where('conversation_id', $conv->id)
                ->orderBy('created_at', 'desc')
                ->first();

            $nbNonLus = DB::table('chat_messages')
                ->where('conversation_id', $conv->id)
                ->where('user_id', '!=', $user->id)
                ->whereRaw("JSON_SEARCH(lu_par, 'one', ?) IS NULL", [(string)$user->id])
                ->count();

            // Pour l'admin : nom de l'entreprise depuis mykolluwork
            $entreprise = null;
            if ($isSuperAdmin && $conv->contact_id) {
                try {
                    $c = DB::connection('workflow')
                        ->table('contacts')
                        ->where('id', $conv->contact_id)
                        ->first();
                    $entreprise = $c ? $c->nom : null;
                } catch (\Exception $e) {}
            }

            return [
                'id'             => $conv->id,
                'titre'          => $entreprise ?? $conv->titre,
                'contact_id'     => $conv->contact_id,
                'dernierMessage' => $lastMsg ? [
                    'message'    => $lastMsg->message,
                    'created_at' => $lastMsg->created_at,
                ] : null,
                'nb_non_lus'     => $nbNonLus,
                'updated_at'     => $conv->updated_at,
                'created_at'     => $conv->created_at,
            ];
        })->toArray();

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

    /**
     * POST /api/chat/conversations
     * Crée (ou retrouve) la conversation de l'entreprise de l'opérateur.
     */
    public function creerConversation(Request $request, Response $response): Response
    {
        $user = $this->getAuthUser($request);
        if (!$user) return $this->error($response, 'UNAUTHORIZED', 'Non authentifié', 401);

        $julien = $this->getJulien();
        if (!$julien) {
            return $this->error($response, 'NOT_FOUND', 'Administrateur introuvable', 404);
        }

        $contactId = $this->getContactId($user);
        if (!$contactId) {
            return $this->error(
                $response,
                'NO_CONTACT',
                'Votre compte n\'est pas rattaché à une entreprise (contact_id manquant sur l\'atelier). Contactez MyKollectOr.',
                422
            );
        }

        $isNew  = false;
        $convId = DB::table('chat_conversations')
            ->where('contact_id', $contactId)
            ->value('id');

        if (!$convId) {
            $convId = $this->getOrCreateConversation($contactId, $julien->id);
            $isNew  = true;
        }

        $this->ensureParticipant($convId, $user->id);

        return $this->success($response, [
            'id'       => $convId,
            'existing' => !$isNew,
        ], $isNew ? 201 : 200);
    }

    /**
     * GET /api/chat/{id}/messages
     * Messages d'une conversation.
     * Vérifie que l'opérateur appartient au même contact_id que la conv,
     * ou qu'il est super_admin.
     */
    public function messages(Request $request, Response $response, array $args): Response
    {
        $user   = $this->getAuthUser($request);
        if (!$user) return $this->error($response, 'UNAUTHORIZED', 'Non authentifié', 401);

        $convId = (int)$args['id'];
        $params = $request->getQueryParams();
        $since  = $params['since'] ?? null;

        if (!$this->canAccessConv($user, $convId)) {
            return $this->error($response, 'FORBIDDEN', 'Accès refusé', 403);
        }

        // S'ajouter comme participant si opérateur de la même entreprise
        $this->ensureParticipant($convId, $user->id);

        $query = DB::table('chat_messages')
            ->join('users', 'users.id', '=', 'chat_messages.user_id')
            ->where('chat_messages.conversation_id', $convId)
            ->select([
                'chat_messages.id',
                'chat_messages.user_id as auteur_id',
                'chat_messages.message',
                'chat_messages.type',
                'chat_messages.reactions',
                'chat_messages.created_at',
                DB::raw("CONCAT(users.prenom, ' ', users.nom) as auteur_nom"),
                'users.role as auteur_role',
            ])
            ->orderBy('chat_messages.created_at', 'asc');

        if ($since) {
            $query->where('chat_messages.created_at', '>', $since);
        }

        $msgs = $query->get()->map(function ($m) {
            return [
                'id'          => $m->id,
                'auteur_id'   => $m->auteur_id,
                'auteur_nom'  => $m->auteur_nom,
                'auteur_role' => $m->auteur_role,
                'message'     => $m->message,
                'type'        => $m->type,
                'reactions'   => $m->reactions ? json_decode($m->reactions, true) : [],
                'created_at'  => $m->created_at,
            ];
        });

        // Marquer comme lus
        DB::table('chat_messages')
            ->where('conversation_id', $convId)
            ->where('user_id', '!=', $user->id)
            ->whereRaw("JSON_SEARCH(lu_par, 'one', ?) IS NULL", [(string)$user->id])
            ->update([
                'lu_par' => DB::raw("JSON_ARRAY_APPEND(COALESCE(lu_par, JSON_ARRAY()), '$', {$user->id})")
            ]);

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

    /**
     * POST /api/chat/{id}/messages
     * Envoyer un message.
     */
    public function envoyer(Request $request, Response $response, array $args): Response
    {
        $user   = $this->getAuthUser($request);
        if (!$user) return $this->error($response, 'UNAUTHORIZED', 'Non authentifié', 401);

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

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

        if (!$this->canAccessConv($user, $convId)) {
            return $this->error($response, 'FORBIDDEN', 'Accès refusé', 403);
        }

        $this->ensureParticipant($convId, $user->id);

        $isSuperAdmin = ($user->role === 'super_admin' || $user->email === 'julien@mykollector.com');
        $type = $isSuperAdmin ? 'mko_reply' : 'message';

        $id = DB::table('chat_messages')->insertGetId([
            'conversation_id' => $convId,
            'user_id'         => $user->id,
            'message'         => $message,
            'type'            => $type,
            'lu_par'          => json_encode([$user->id]),
            'created_at'      => date('Y-m-d H:i:s'),
        ]);

        // Mettre à jour updated_at de la conversation
        DB::table('chat_conversations')
            ->where('id', $convId)
            ->update(['updated_at' => date('Y-m-d H:i:s')]);

        // Si Julien répond, marquer les wizz liés comme répondus
        if ($isSuperAdmin) {
            DB::table('chat_wizz')
                ->where('conversation_id', $convId)
                ->where('repondu', 0)
                ->update([
                    'repondu'    => 1,
                    'repondu_at' => date('Y-m-d H:i:s'),
                ]);
        }

        return $this->success($response, [
            'id'          => $id,
            'auteur_id'   => $user->id,
            'auteur_nom'  => trim(($user->prenom ?? '') . ' ' . ($user->nom ?? '')),
            'auteur_role' => $user->role,
            'message'     => $message,
            'type'        => $type,
            'reactions'   => [],
            'created_at'  => date('Y-m-d H:i:s'),
        ], 201);
    }

    /**
     * POST /api/chat/{id}/wizz
     * Envoie un email à Julien avec contexte + enregistre en table chat_wizz.
     */
    public function wizz(Request $request, Response $response, array $args): Response
    {
        $user   = $this->getAuthUser($request);
        if (!$user) return $this->error($response, 'UNAUTHORIZED', 'Non authentifié', 401);

        $convId = (int)$args['id'];

        if (!$this->canAccessConv($user, $convId)) {
            return $this->error($response, 'FORBIDDEN', 'Accès refusé', 403);
        }

        // Anti-spam : 1 wizz par 10 min par conversation
        $lastWizz = DB::table('chat_wizz')
            ->where('conversation_id', $convId)
            ->where('created_at', '>=', date('Y-m-d H:i:s', strtotime('-10 minutes')))
            ->exists();

        if ($lastWizz) {
            return $this->error($response, 'RATE_LIMIT', 'Un wizz a déjà été envoyé récemment — attendez quelques minutes.', 429);
        }

        // Dernier message pour contexte
        $lastMsg = DB::table('chat_messages')
            ->where('conversation_id', $convId)
            ->orderBy('created_at', 'desc')
            ->first();

        $conv = DB::table('chat_conversations')->where('id', $convId)->first();
        $contactId = $conv?->contact_id;

        // Enregistrer en BDD
        $wizzId = DB::table('chat_wizz')->insertGetId([
            'conversation_id' => $convId,
            'contact_id'      => $contactId ?? 0,
            'user_id'         => $user->id,
            'message_context' => $lastMsg?->message,
            'repondu'         => 0,
            'created_at'      => date('Y-m-d H:i:s'),
        ]);

        $expediteur = trim(($user->prenom ?? '') . ' ' . ($user->nom ?? '')) ?: $user->email;
        $entreprise = $conv?->titre ?? 'Entreprise inconnue';

        $mail = new MailService();
        $sent = $mail->wizz(
            'julien@mykollector.com',
            'Julien',
            $expediteur,
            $user->email,
            $convId,
            $wizzId,
            $entreprise,
            $lastMsg?->message
        );

        $this->logAudit($user->id, 'chat_wizz', 'chat_conversations', $convId, [], $request);

        return $this->success($response, ['sent' => $sent, 'wizz_id' => $wizzId]);
    }

    /**
     * POST /api/chat/wizz/{wizzId}/repondre
     * Julien répond à un wizz — le message est posté dans le fil de l'entreprise.
     */
    public function repondreWizz(Request $request, Response $response, array $args): Response
    {
        $user = $this->getAuthUser($request);
        if (!$user) return $this->error($response, 'UNAUTHORIZED', 'Non authentifié', 401);

        $isSuperAdmin = ($user->role === 'super_admin' || $user->email === 'julien@mykollector.com');
        if (!$isSuperAdmin) return $this->error($response, 'FORBIDDEN', 'Réservé à Julien', 403);

        $wizzId = (int)$args['wizzId'];
        $body   = (array)$request->getParsedBody();
        $message = trim($body['message'] ?? '');

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

        $wizz = DB::table('chat_wizz')->where('id', $wizzId)->first();
        if (!$wizz) return $this->error($response, 'NOT_FOUND', 'Wizz introuvable', 404);

        $convId = $wizz->conversation_id;

        // Poster le message dans le fil comme mko_reply
        $msgId = DB::table('chat_messages')->insertGetId([
            'conversation_id' => $convId,
            'user_id'         => $user->id,
            'message'         => $message,
            'type'            => 'mko_reply',
            'lu_par'          => json_encode([$user->id]),
            'created_at'      => date('Y-m-d H:i:s'),
        ]);

        DB::table('chat_conversations')
            ->where('id', $convId)
            ->update(['updated_at' => date('Y-m-d H:i:s')]);

        // Marquer le wizz et tous les wizz pendants de cette conv comme répondus
        DB::table('chat_wizz')
            ->where('conversation_id', $convId)
            ->where('repondu', 0)
            ->update([
                'repondu'    => 1,
                'repondu_at' => date('Y-m-d H:i:s'),
            ]);

        return $this->success($response, [
            'message_id' => $msgId,
            'conv_id'    => $convId,
        ]);
    }

    /**
     * GET /api/chat/wizz/pending
     * Julien : liste des wizz non répondus.
     */
    public function wizzPending(Request $request, Response $response): Response
    {
        $user = $this->getAuthUser($request);
        if (!$user) return $this->error($response, 'UNAUTHORIZED', 'Non authentifié', 401);

        $isSuperAdmin = ($user->role === 'super_admin' || $user->email === 'julien@mykollector.com');
        if (!$isSuperAdmin) return $this->error($response, 'FORBIDDEN', 'Réservé à Julien', 403);

        $wizz = DB::table('chat_wizz as w')
            ->join('users as u', 'u.id', '=', 'w.user_id')
            ->join('chat_conversations as c', 'c.id', '=', 'w.conversation_id')
            ->where('w.repondu', 0)
            ->select([
                'w.id',
                'w.conversation_id',
                'w.contact_id',
                'w.message_context',
                'w.created_at',
                'c.titre as entreprise',
                DB::raw("CONCAT(u.prenom, ' ', u.nom) as operateur_nom"),
                'u.email as operateur_email',
            ])
            ->orderBy('w.created_at', 'desc')
            ->get();

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

    /**
     * POST /api/chat/{id}/reactions/{msgId}
     * Toggle réaction 👍 sur un message.
     */
    public function toggleReaction(Request $request, Response $response, array $args): Response
    {
        $user  = $this->getAuthUser($request);
        if (!$user) return $this->error($response, 'UNAUTHORIZED', 'Non authentifié', 401);

        $convId = (int)$args['id'];
        $msgId  = (int)$args['msgId'];
        $body   = (array)$request->getParsedBody();
        $emoji  = $body['emoji'] ?? '👍';

        // Valider emoji autorisé
        if (!in_array($emoji, ['👍', '❤️', '✅'], true)) {
            return $this->error($response, 'VALIDATION_ERROR', 'Réaction non autorisée', 400);
        }

        if (!$this->canAccessConv($user, $convId)) {
            return $this->error($response, 'FORBIDDEN', 'Accès refusé', 403);
        }

        $msg = DB::table('chat_messages')
            ->where('id', $msgId)
            ->where('conversation_id', $convId)
            ->first();

        if (!$msg) return $this->error($response, 'NOT_FOUND', 'Message introuvable', 404);

        $reactions = $msg->reactions ? json_decode($msg->reactions, true) : [];
        $users = $reactions[$emoji] ?? [];

        if (in_array($user->id, $users)) {
            $users = array_values(array_filter($users, fn($id) => $id !== $user->id));
        } else {
            $users[] = $user->id;
        }

        $reactions[$emoji] = $users;
        if (empty($reactions[$emoji])) unset($reactions[$emoji]);

        DB::table('chat_messages')
            ->where('id', $msgId)
            ->update(['reactions' => json_encode($reactions)]);

        return $this->success($response, ['reactions' => $reactions]);
    }

    // ─────────────────────────────────────────────────────────
    // CONTRÔLE D'ACCÈS
    // ─────────────────────────────────────────────────────────

    private function canAccessConv(object $user, int $convId): bool
    {
        // Super admin : accès à tout
        if ($user->role === 'super_admin' || $user->email === 'julien@mykollector.com') {
            return true;
        }

        // Opérateur : vérifier que la conv appartient à son contact_id
        $contactId = $this->getContactId($user);
        if (!$contactId) return false;

        return DB::table('chat_conversations')
            ->where('id', $convId)
            ->where('contact_id', $contactId)
            ->exists();
    }
}
