<?php

namespace App\Controllers;

use App\Core\Controller;
use App\Config\Database;
use App\Middleware\AuthMiddleware;
use PDO;

class ConversationController extends Controller {
    private $db;

    public function __construct() {
        $this->db = Database::getInstance()->getConnection();
    }

    private function logDebug($message, $data = []) {
        $logFile = __DIR__ . '/../../public/debug_log.txt';
        $timestamp = date('Y-m-d H:i:s');
        $logEntry = "[$timestamp] $message " . json_encode($data) . "\n";
        file_put_contents($logFile, $logEntry, FILE_APPEND);
    }

    private function resolveUserId($userId) {
        if (!is_string($userId) || strpos($userId, 'guest:') !== 0) {
            return (int)$userId;
        }

        $parts = explode(':', $userId, 4);
        if (count($parts) < 3) {
            return 0;
        }

        $ownerId = (int)$parts[1];
        $visitorHash = $parts[2];
        $anonLabel = isset($parts[3]) && $parts[3] ? $parts[3] : ('Anon' . rand(100, 999));

        if (preg_match('/^user_stable_(\d+)$/', $visitorHash, $m)) {
            $stableUserId = (int)$m[1];
            $stmt = $this->db->prepare("SELECT id FROM users WHERE id = ? LIMIT 1");
            $stmt->execute([$stableUserId]);
            if ($stmt->fetch(PDO::FETCH_ASSOC)) {
                return $stableUserId;
            }
        }

        $stmt = $this->db->prepare("SELECT id, anon_label FROM anonymous_sessions WHERE owner_user_id = ? AND visitor_hash = ?");
        $stmt->execute([$ownerId, $visitorHash]);
        $session = $stmt->fetch(PDO::FETCH_ASSOC);
        if (!$session) {
            $stmt = $this->db->prepare("INSERT INTO anonymous_sessions (owner_user_id, visitor_hash, anon_label) VALUES (?, ?, ?)");
            $stmt->execute([$ownerId, $visitorHash, $anonLabel]);
        } else {
            $anonLabel = $session['anon_label'] ?: $anonLabel;
        }

        $uniqueString = $ownerId . "_" . $visitorHash;
        $shadowUsername = "anon_" . md5($uniqueString);

        $stmt = $this->db->prepare("SELECT id FROM users WHERE username = ?");
        $stmt->execute([$shadowUsername]);
        $shadowUser = $stmt->fetch(PDO::FETCH_ASSOC);
        if ($shadowUser) {
            return (int)$shadowUser['id'];
        }

        $email = $shadowUsername . '@anon.local';
        $passwordHash = password_hash(bin2hex(random_bytes(16)), PASSWORD_BCRYPT);
        $linkSlug = $shadowUsername;

        $stmt = $this->db->prepare("INSERT INTO users (email, password_hash, username, display_name, link_slug, status) VALUES (?, ?, ?, ?, ?, 'offline')");
        $stmt->execute([$email, $passwordHash, $shadowUsername, $anonLabel, $linkSlug]);
        return (int)$this->db->lastInsertId();
    }

    public function index() {
        try {
            $rawUserId = AuthMiddleware::authenticate();
            $userId = $this->resolveUserId($rawUserId);
            $this->logDebug('CONV INDEX', ['rawUser' => $rawUserId, 'resolvedUser' => $userId]);

            if ($userId === 0) {
                $this->json([]);
                return;
            }

            $stmtUser = $this->db->prepare("SELECT chat_history_cleared_at FROM users WHERE id = ? LIMIT 1");
            $stmtUser->execute([$userId]);
            $userRow = $stmtUser->fetch(PDO::FETCH_ASSOC);
            $globalClear = ($userRow && $userRow['chat_history_cleared_at']) ? $userRow['chat_history_cleared_at'] : '1970-01-01 00:00:00';

            $sql = "
                SELECT c.*,
                    u1.username as user_a_username, u1.display_name as user_a_name, u1.avatar_url as user_a_avatar, u1.is_plus_subscriber as user_a_is_plus,
                    u2.username as user_b_username, u2.display_name as user_b_name, u2.avatar_url as user_b_avatar, u2.is_plus_subscriber as user_b_is_plus,
                    m.body_text as last_message, m.created_at as last_message_time, m.sender_id as last_sender_id, m.is_read,
                    m.is_anonymous as last_msg_is_anon, m.sender_alias as last_msg_alias
                FROM conversations c
                LEFT JOIN users u1 ON c.user_a_id = u1.id
                LEFT JOIN users u2 ON c.user_b_id = u2.id
                LEFT JOIN messages m ON c.last_message_id = m.id
                LEFT JOIN conversation_clears cc ON cc.conversation_id = c.id AND cc.user_id = ?
                WHERE (c.user_a_id = ? OR c.user_b_id = ?)
                  AND COALESCE(c.last_message_at, c.updated_at, c.created_at) > ?
                  AND COALESCE(c.last_message_at, c.updated_at, c.created_at) > COALESCE(cc.cleared_at, '1970-01-01 00:00:00')
                ORDER BY c.last_message_at DESC, c.id DESC
            ";

            $stmt = $this->db->prepare($sql);
            // Params: cc.user_id, c.user_a_id, c.user_b_id, globalClear
            $stmt->execute([$userId, $userId, $userId, $globalClear]);
            $conversations = $stmt->fetchAll(PDO::FETCH_ASSOC);
            $this->logDebug('CONV INDEX ROWS', ['count' => count($conversations)]);

            $formatted = [];

            foreach ($conversations as $c) {
                $isUserA = ((int)$c['user_a_id'] === (int)$userId);

                $partnerDbId = $isUserA ? (int)$c['user_b_id'] : (int)$c['user_a_id'];
                $partnerUsername = $isUserA ? $c['user_b_username'] : $c['user_a_username'];
                $partnerName = $isUserA ? ($c['user_b_name'] ?? null) : ($c['user_a_name'] ?? null);
                $partnerAvatar = $isUserA ? ($c['user_b_avatar'] ?? null) : ($c['user_a_avatar'] ?? null);
                $partnerIsPlus = $isUserA ? (int)($c['user_b_is_plus'] ?? 0) : (int)($c['user_a_is_plus'] ?? 0);

                $displayName = $partnerName ?: ($partnerUsername ?: 'Unknown');
                $displayImage = $partnerAvatar;
                $partnerId = $partnerDbId;

                $isAnonymousConv = ((int)$c['is_anonymous'] === 1);
                if ($isAnonymousConv) {
                    $anonParticipantId = isset($c['anonymous_participant_id']) ? (int)$c['anonymous_participant_id'] : 0;
                    $shouldMask = ($anonParticipantId !== 0 && $anonParticipantId !== (int)$userId);
                    if (!$shouldMask && $anonParticipantId === 0) {
                        $shouldMask = ((int)($c['last_msg_is_anon'] ?? 0) === 1) && ((int)($c['last_sender_id'] ?? 0) === $partnerDbId);
                    }

                    if ($shouldMask) {
                        $alias = $c['anonymous_alias'] ?: ($c['last_msg_alias'] ?: 'Anonim');
                        $displayName = $alias;
                        $displayImage = 'https://ui-avatars.com/api/?name=Anon&background=000&color=fff';
                        $partnerId = 0;
                    }
                }

                $lastSenderId = isset($c['last_sender_id']) ? (int)$c['last_sender_id'] : 0;
                $isRead = isset($c['is_read']) ? (int)$c['is_read'] : 1;
                $unreadCount = ($lastSenderId !== 0 && $lastSenderId !== (int)$userId && $isRead === 0) ? 1 : 0;

                $formatted[] = [
                    'id' => (int)$c['id'],
                    'partner_id' => $partnerId,
                    'display_name' => $displayName,
                    'display_image' => $displayImage,
                    'other_user' => [
                        'id' => $partnerId,
                        'username' => $partnerUsername,
                        'display_name' => $displayName,
                        'avatar_url' => $displayImage,
                        'is_plus_subscriber' => ($partnerId === 0) ? 0 : $partnerIsPlus,
                        'status' => 'online',
                        'is_online' => true,
                    ],
                    'last_message' => $c['last_message'],
                    'last_message_at' => $c['last_message_time'] ?? $c['last_message_at'] ?? $c['updated_at'],
                    'unread_count' => $unreadCount,
                    'is_anonymous' => $isAnonymousConv
                ];
            }

            $this->json($formatted);
        } catch (\Exception $e) {
            $this->logDebug('CONV INDEX ERROR', ['error' => $e->getMessage()]);
            $this->json(['error' => 'Server Error'], 500);
        }
    }

    public function show($id) {
        try {
            $rawUserId = AuthMiddleware::authenticate();
            $userId = $this->resolveUserId($rawUserId);
            $this->logDebug('CONV SHOW', ['id' => (int)$id, 'rawUser' => $rawUserId, 'resolvedUser' => $userId]);

            if ($userId === 0) {
                $this->json(['error' => 'Access denied'], 403);
                return;
            }

            $sql = "
                SELECT c.*,
                    u1.username as user_a_username, u1.display_name as user_a_name, u1.avatar_url as user_a_avatar, u1.is_plus_subscriber as user_a_is_plus,
                    u2.username as user_b_username, u2.display_name as user_b_name, u2.avatar_url as user_b_avatar, u2.is_plus_subscriber as user_b_is_plus
                FROM conversations c
                LEFT JOIN users u1 ON c.user_a_id = u1.id
                LEFT JOIN users u2 ON c.user_b_id = u2.id
                WHERE c.id = ? AND (c.user_a_id = ? OR c.user_b_id = ?)
                LIMIT 1
            ";
            $stmt = $this->db->prepare($sql);
            $stmt->execute([(int)$id, $userId, $userId]);
            $c = $stmt->fetch(PDO::FETCH_ASSOC);

            if (!$c) {
                $this->json(['error' => 'Conversation not found'], 404);
                return;
            }

            $isUserA = ((int)$c['user_a_id'] === (int)$userId);

            $partnerDbId = $isUserA ? (int)$c['user_b_id'] : (int)$c['user_a_id'];
            $partnerUsername = $isUserA ? $c['user_b_username'] : $c['user_a_username'];
            $partnerName = $isUserA ? ($c['user_b_name'] ?? null) : ($c['user_a_name'] ?? null);
            $partnerAvatar = $isUserA ? ($c['user_b_avatar'] ?? null) : ($c['user_a_avatar'] ?? null);
            $partnerIsPlus = $isUserA ? (int)($c['user_b_is_plus'] ?? 0) : (int)($c['user_a_is_plus'] ?? 0);


            $displayName = $partnerName ?: ($partnerUsername ?: 'Unknown');
            $displayImage = $partnerAvatar;
            $partnerId = $partnerDbId;

            $isAnonymousConv = ((int)$c['is_anonymous'] === 1);
            if ($isAnonymousConv) {
                $anonParticipantId = isset($c['anonymous_participant_id']) ? (int)$c['anonymous_participant_id'] : 0;
                $shouldMask = ($anonParticipantId !== 0 && $anonParticipantId !== (int)$userId);
                if (!$shouldMask && $anonParticipantId === 0) {
                    $shouldMask = true;
                }
                if ($shouldMask) {
                    $displayName = $c['anonymous_alias'] ?: 'Anonim';
                    $displayImage = 'https://ui-avatars.com/api/?name=Anon&background=000&color=fff';
                    $partnerId = 0;
                }
            }

            $this->json([
                'id' => (int)$c['id'],
                'partner_id' => $partnerId,
                'display_name' => $displayName,
                'display_image' => $displayImage,
                'other_user' => [
                    'id' => $partnerId,
                    'username' => $partnerUsername,
                    'display_name' => $displayName,
                    'avatar_url' => $displayImage,
                    'is_plus_subscriber' => ($partnerId === 0) ? 0 : $partnerIsPlus,
                    'status' => 'online',
                    'is_online' => true,
                ],
                'created_at' => $c['created_at'],
                'is_anonymous' => $isAnonymousConv
            ]);
        } catch (\Exception $e) {
            $this->logDebug('CONV SHOW ERROR', ['error' => $e->getMessage()]);
            $this->json(['error' => 'Server Error'], 500);
        }
    }

    public function clear($id) {
        try {
            $rawUserId = AuthMiddleware::authenticate();
            $userId = $this->resolveUserId($rawUserId);
            if ($userId === 0) {
                $this->json(['error' => 'Access denied'], 403);
                return;
            }

            $conversationId = (int)$id;
            if ($conversationId <= 0) {
                $this->json(['error' => 'Invalid conversation'], 422);
                return;
            }

            $stmt = $this->db->prepare("SELECT id FROM conversations WHERE id = ? AND (user_a_id = ? OR user_b_id = ?) LIMIT 1");
            $stmt->execute([$conversationId, $userId, $userId]);
            if (!$stmt->fetch(PDO::FETCH_ASSOC)) {
                $this->json(['error' => 'Conversation not found'], 404);
                return;
            }

            $stmt = $this->db->prepare("
                INSERT INTO conversation_clears (user_id, conversation_id, cleared_at)
                VALUES (?, ?, NOW())
                ON DUPLICATE KEY UPDATE cleared_at = NOW()
            ");
            $stmt->execute([$userId, $conversationId]);

            $this->json(['success' => true, 'message' => 'Chat history cleared']);
        } catch (\Exception $e) {
            $this->logDebug('CONV CLEAR ERROR', ['error' => $e->getMessage()]);
            $this->json(['error' => 'Server Error'], 500);
        }
    }

    public function clearAll() {
        try {
            $rawUserId = AuthMiddleware::authenticate();
            $userId = $this->resolveUserId($rawUserId);
            if ($userId === 0) {
                $this->json(['error' => 'Access denied'], 403);
                return;
            }

            $stmt = $this->db->prepare("UPDATE users SET chat_history_cleared_at = NOW() WHERE id = ?");
            $stmt->execute([$userId]);

            $this->json(['success' => true, 'message' => 'All chat history cleared']);
        } catch (\Exception $e) {
            $this->logDebug('CONV CLEAR_ALL ERROR', ['error' => $e->getMessage()]);
            $this->json(['error' => 'Server Error'], 500);
        }
    }
}
