<?php

namespace Modules\Messaging\Controllers;

use App\Controllers\BaseController;
use App\Models\MessageConversationModel;
use App\Models\MessageModel;
use App\Models\MessageParticipantModel;
use Modules\Messaging\Services\MessagingService;

class MessageController extends BaseController
{
    protected MessageConversationModel $conversations;
    protected MessageParticipantModel $participants;
    protected MessageModel $messages;
    protected MessagingService $service;

    public function initController(\CodeIgniter\HTTP\RequestInterface $request, \CodeIgniter\HTTP\ResponseInterface $response, \Psr\Log\LoggerInterface $logger)
    {
        parent::initController($request, $response, $logger);
        $this->conversations = new MessageConversationModel();
        $this->participants  = new MessageParticipantModel();
        $this->messages      = new MessageModel();
        $this->service       = new MessagingService();
    }

    public function index()
    {
        $userId = (int) $this->session->get('user_id');
        $list   = $this->conversations->listForUser($userId);

        // Ensure public channel exists even if SQL seed was skipped
        if (! $this->conversations->getPublicChannel()) {
            $this->conversations->insert([
                'type'        => 'public',
                'name'        => 'Public',
                'description' => 'Company-wide public channel — everyone can read and post.',
                'is_system'   => 1,
            ]);
            $list = $this->conversations->listForUser($userId);
        }

        $activeId = (int) ($this->request->getGet('c') ?? 0);
        if (! $activeId && $list) {
            $activeId = (int) $list[0]['id'];
        }

        $active       = null;
        $thread       = [];
        $activeTitle  = '';
        $members      = [];

        if ($activeId) {
            $active = $this->conversations->find($activeId);
            if ($active && $this->service->userCanAccess($active, $userId)) {
                $thread = $this->messages->getForConversation($activeId);
                $this->participants->markRead($activeId, $userId);
                $activeTitle = $this->service->displayTitle(
                    array_merge($active, $this->findListMeta($list, $activeId)),
                    $userId
                );
                if ($active['type'] === 'group') {
                    $members = $this->participants->getMembersWithNames($activeId);
                }
            } else {
                $active      = null;
                $activeId    = 0;
                $activeTitle = '';
            }
        }

        return view('Modules\Messaging\Views\messages\index', array_merge($this->baseViewData(), [
            'title'         => 'Messages',
            'conversations' => $list,
            'activeId'      => $activeId,
            'active'        => $active,
            'activeTitle'   => $activeTitle,
            'thread'        => $thread,
            'members'       => $members,
            'users'         => $this->service->listActiveUsers($userId),
        ]));
    }

    public function startDirect()
    {
        $userId = (int) $this->session->get('user_id');
        $peerId = (int) $this->request->getPost('peer_user_id');

        $result = $this->service->startDirect($userId, $peerId);
        if (! $result['success']) {
            return redirect()->to('/messages')->with('error', $result['error'] ?? 'Could not start conversation.');
        }

        return redirect()->to('/messages?c=' . $result['id'])->with('success', 'Conversation ready.');
    }

    public function send(int $id)
    {
        $userId = (int) $this->session->get('user_id');
        $body   = (string) $this->request->getPost('body');
        $wantsJson = $this->request->isAJAX()
            || str_contains((string) $this->request->getHeaderLine('Accept'), 'application/json');

        $result = $this->service->send($id, $userId, $body);

        if ($wantsJson) {
            if (! $result['success']) {
                return $this->response->setStatusCode(422)->setJSON([
                    'success' => false,
                    'error'   => $result['error'] ?? 'Could not send.',
                    'errors'  => $result['errors'] ?? [],
                ]);
            }

            return $this->response->setJSON([
                'success' => true,
                'message' => $this->formatMessagePayload($result['message']),
            ]);
        }

        if (! $result['success']) {
            return redirect()->to('/messages?c=' . $id)->with('error', $result['error'] ?? 'Could not send message.');
        }

        return redirect()->to('/messages?c=' . $id);
    }

    public function poll(int $id)
    {
        $userId  = (int) $this->session->get('user_id');
        $afterId = (int) ($this->request->getGet('after') ?? 0);

        $conversation = $this->conversations->find($id);
        if (! $conversation || ! $this->service->userCanAccess($conversation, $userId)) {
            return $this->response->setStatusCode(403)->setJSON(['success' => false, 'error' => 'Forbidden']);
        }

        $rows = $this->messages->getForConversation($id, $afterId ?: null, 50);
        $this->participants->markRead($id, $userId);

        return $this->response->setJSON([
            'success'  => true,
            'messages' => array_map(fn ($m) => $this->formatMessagePayload($m), $rows),
        ]);
    }

    /**
     * @param list<array<string, mixed>> $list
     * @return array<string, mixed>
     */
    protected function findListMeta(array $list, int $id): array
    {
        foreach ($list as $row) {
            if ((int) $row['id'] === $id) {
                return $row;
            }
        }

        return [];
    }

    /**
     * @param array<string, mixed>|null $message
     * @return array<string, mixed>
     */
    protected function formatMessagePayload(?array $message): array
    {
        if (! $message) {
            return [];
        }

        $name = trim(($message['first_name'] ?? '') . ' ' . ($message['last_name'] ?? ''));
        if ($name === '') {
            $name = (string) ($message['username'] ?? 'User');
        }

        return [
            'id'         => (int) $message['id'],
            'sender_id'  => (int) $message['sender_id'],
            'body'       => (string) $message['body'],
            'created_at' => (string) $message['created_at'],
            'sender'     => $name,
            'is_mine'    => (int) $message['sender_id'] === (int) $this->session->get('user_id'),
        ];
    }
}
