<?php
/**
 * FinoviaPay Telegram Bot
 * Customer Feedback / Poll Functions
 *
 * Step 4 updated working file
 * Includes:
 * - vote handling
 * - duplicate vote check
 * - poll active / closed / expired validation
 * - professional result display after vote
 * - optional comment flow after result
 * - initial_vote_count + actual live votes result logic
 */

if (!function_exists('bfp_db')) {

    function bfp_comment_state_file() {
        return __DIR__ . '/bot_feedback_poll_comment_state.json';
    }

    function bfp_db() {
        global $pdo, $conn;

        if (isset($pdo) && $pdo instanceof PDO) {
            return ['type' => 'pdo', 'db' => $pdo];
        }

        if (isset($conn) && $conn instanceof mysqli) {
            return ['type' => 'mysqli', 'db' => $conn];
        }

        die('Database connection not found in config.php');
    }

    function bfp_fetch($sql, array $params = []) {
        $db = bfp_db();

        if ($db['type'] === 'pdo') {
            $stmt = $db['db']->prepare($sql);
            $stmt->execute($params);
            return $stmt->fetch(PDO::FETCH_ASSOC);
        }

        $stmt = $db['db']->prepare($sql);
        if (!$stmt) {
            return null;
        }

        if (!empty($params)) {
            $types = '';
            $bind = [];

            foreach ($params as $param) {
                if (is_int($param)) $types .= 'i';
                elseif (is_float($param)) $types .= 'd';
                else $types .= 's';
                $bind[] = $param;
            }

            $stmt->bind_param($types, ...$bind);
        }

        $stmt->execute();
        $result = $stmt->get_result();
        $row = $result ? $result->fetch_assoc() : null;
        $stmt->close();

        return $row;
    }

    function bfp_fetch_all($sql, array $params = []) {
        $db = bfp_db();

        if ($db['type'] === 'pdo') {
            $stmt = $db['db']->prepare($sql);
            $stmt->execute($params);
            return $stmt->fetchAll(PDO::FETCH_ASSOC);
        }

        $stmt = $db['db']->prepare($sql);
        if (!$stmt) {
            return [];
        }

        if (!empty($params)) {
            $types = '';
            $bind = [];

            foreach ($params as $param) {
                if (is_int($param)) $types .= 'i';
                elseif (is_float($param)) $types .= 'd';
                else $types .= 's';
                $bind[] = $param;
            }

            $stmt->bind_param($types, ...$bind);
        }

        $stmt->execute();
        $result = $stmt->get_result();
        $rows = [];

        if ($result) {
            while ($row = $result->fetch_assoc()) {
                $rows[] = $row;
            }
        }

        $stmt->close();
        return $rows;
    }

    function bfp_exec($sql, array $params = []) {
        $db = bfp_db();

        if ($db['type'] === 'pdo') {
            $stmt = $db['db']->prepare($sql);
            $ok = $stmt->execute($params);

            return [
                'ok' => $ok,
                'insert_id' => $ok ? $db['db']->lastInsertId() : null,
                'error' => $ok ? '' : (($stmt->errorInfo()[2] ?? 'Database error'))
            ];
        }

        $stmt = $db['db']->prepare($sql);
        if (!$stmt) {
            return [
                'ok' => false,
                'insert_id' => null,
                'error' => 'MySQLi prepare failed: ' . $db['db']->error
            ];
        }

        if (!empty($params)) {
            $types = '';
            $bind = [];

            foreach ($params as $param) {
                if (is_int($param)) $types .= 'i';
                elseif (is_float($param)) $types .= 'd';
                else $types .= 's';
                $bind[] = $param;
            }

            $stmt->bind_param($types, ...$bind);
        }

        $ok = $stmt->execute();
        $insertId = $ok ? $stmt->insert_id : null;
        $error = $stmt->error;
        $stmt->close();

        return [
            'ok' => $ok,
            'insert_id' => $insertId,
            'error' => $error
        ];
    }

    function bfp_get_user_by_chat_id($chatId) {
        return bfp_fetch(
            "SELECT *
             FROM bot_join_logs
             WHERE telegram_chat_id = ?
             LIMIT 1",
            [(string)$chatId]
        );
    }

    function bfp_get_poll($pollId) {
        return bfp_fetch(
            "SELECT *
             FROM bot_feedback_polls
             WHERE id = ?
             LIMIT 1",
            [(int)$pollId]
        );
    }

    function bfp_get_active_poll($pollId) {
        $poll = bfp_get_poll($pollId);

        if (!$poll) {
            return ['ok' => false, 'reason' => 'unavailable', 'poll' => null];
        }

        if (!isset($poll['status']) || $poll['status'] !== 'active') {
            if (isset($poll['status']) && $poll['status'] === 'closed') {
                return ['ok' => false, 'reason' => 'closed', 'poll' => $poll];
            }
            if (isset($poll['status']) && $poll['status'] === 'expired') {
                return ['ok' => false, 'reason' => 'expired', 'poll' => $poll];
            }
            return ['ok' => false, 'reason' => 'unavailable', 'poll' => $poll];
        }

        $now = time();

        if (!empty($poll['start_at'])) {
            $start = strtotime($poll['start_at']);
            if ($start !== false && $now < $start) {
                return ['ok' => false, 'reason' => 'unavailable', 'poll' => $poll];
            }
        }

        if (!empty($poll['expires_at'])) {
            $end = strtotime($poll['expires_at']);
            if ($end !== false && $now > $end) {
                return ['ok' => false, 'reason' => 'expired', 'poll' => $poll];
            }
        }

        return ['ok' => true, 'reason' => 'active', 'poll' => $poll];
    }

    function bfp_get_poll_option($pollId, $optionId) {
        return bfp_fetch(
            "SELECT *
             FROM bot_feedback_poll_options
             WHERE poll_id = ?
               AND id = ?
               AND status = 'active'
             LIMIT 1",
            [(int)$pollId, (int)$optionId]
        );
    }

    function bfp_already_voted($pollId, $userId) {
        $row = bfp_fetch(
            "SELECT id
             FROM bot_feedback_poll_votes
             WHERE poll_id = ?
               AND user_id = ?
             LIMIT 1",
            [(int)$pollId, (int)$userId]
        );

        return $row ? true : false;
    }

    function bfp_get_vote_row($pollId, $userId) {
        return bfp_fetch(
            "SELECT *
             FROM bot_feedback_poll_votes
             WHERE poll_id = ?
               AND user_id = ?
             LIMIT 1",
            [(int)$pollId, (int)$userId]
        );
    }

    function bfp_save_vote($pollId, $optionId, $userId, $chatId) {
        return bfp_exec(
            "INSERT INTO bot_feedback_poll_votes
            (poll_id, option_id, user_id, telegram_chat_id, response_source, voted_at, created_at)
            VALUES (?, ?, ?, ?, 'telegram', NOW(), NOW())",
            [(int)$pollId, (int)$optionId, (int)$userId, (string)$chatId]
        );
    }

    function bfp_save_comment($pollId, $userId, $commentText) {
        return bfp_exec(
            "UPDATE bot_feedback_poll_votes
             SET comment_text = ?
             WHERE poll_id = ?
               AND user_id = ?
             LIMIT 1",
            [(string)$commentText, (int)$pollId, (int)$userId]
        );
    }

    function bfp_mark_notification_clicked($pollId, $userId) {
        return bfp_exec(
            "UPDATE bot_feedback_poll_notifications
             SET delivery_status = CASE
                    WHEN delivery_status IN ('pending','sent','read') THEN 'clicked'
                    ELSE delivery_status
                 END,
                 clicked_at = NOW()
             WHERE poll_id = ?
               AND user_id = ?",
            [(int)$pollId, (int)$userId]
        );
    }

    function bfp_read_comment_states() {
        $file = bfp_comment_state_file();

        if (!file_exists($file)) {
            return [];
        }

        $raw = @file_get_contents($file);
        if ($raw === false || $raw === '') {
            return [];
        }

        $data = json_decode($raw, true);
        return is_array($data) ? $data : [];
    }

    function bfp_write_comment_states(array $data) {
        $file = bfp_comment_state_file();
        return @file_put_contents($file, json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT), LOCK_EX) !== false;
    }

    function bfp_set_pending_comment_state($chatId, $pollId, $userId) {
        $states = bfp_read_comment_states();
        $states[(string)$chatId] = [
            'poll_id' => (int)$pollId,
            'user_id' => (int)$userId,
            'created_at' => date('Y-m-d H:i:s')
        ];
        return bfp_write_comment_states($states);
    }

    function bfp_get_pending_comment_state($chatId) {
        $states = bfp_read_comment_states();
        return isset($states[(string)$chatId]) ? $states[(string)$chatId] : null;
    }

    function bfp_clear_pending_comment_state($chatId) {
        $states = bfp_read_comment_states();
        if (isset($states[(string)$chatId])) {
            unset($states[(string)$chatId]);
            return bfp_write_comment_states($states);
        }
        return true;
    }

    function bfp_get_poll_results_summary($pollId) {
        return bfp_fetch_all(
            "SELECT
                o.id,
                o.option_text,
                COALESCE(o.initial_vote_count, 0) AS initial_vote_count,
                COALESCE(v.actual_votes, 0) AS actual_votes
             FROM bot_feedback_poll_options o
             LEFT JOIN (
                SELECT option_id, COUNT(*) AS actual_votes
                FROM bot_feedback_poll_votes
                WHERE poll_id = ?
                GROUP BY option_id
             ) v ON v.option_id = o.id
             WHERE o.poll_id = ?
             ORDER BY o.sort_order ASC, o.id ASC",
            [(int)$pollId, (int)$pollId]
        );
    }

    function bfp_build_display_result_rows(array $options) {
        $rows = [];
        $totalDisplayVotes = 0;

        foreach ($options as $opt) {
            $initialVotes = isset($opt['initial_vote_count']) ? (int)$opt['initial_vote_count'] : 0;
            $actualVotes = isset($opt['actual_votes']) ? (int)$opt['actual_votes'] : 0;
            $displayVotes = $initialVotes + $actualVotes;

            $row = $opt;
            $row['display_votes'] = $displayVotes;
            $rows[] = $row;

            $totalDisplayVotes += $displayVotes;
        }

        return [
            'rows' => $rows,
            'total_display_votes' => $totalDisplayVotes
        ];
    }

    function bfp_build_result_message($pollTitle, array $displayRows, $totalDisplayVotes) {
        $message = "📊 <b>FinoviaPay Feedback Result</b>\n\n";
        $message .= $pollTitle . "\n\n";

        foreach ($displayRows as $opt) {
            $votes = isset($opt['display_votes']) ? (int)$opt['display_votes'] : 0;
            $percent = $totalDisplayVotes > 0 ? round(($votes / $totalDisplayVotes) * 100) : 0;
            $message .= "✔ " . $opt['option_text'] . " — " . $percent . "% (" . $votes . " votes)\n";
        }

        $message .= "\nTotal Responses: " . $totalDisplayVotes . "\n\n";
        $message .= "— FinoviaPay\n";
        $message .= "Worldwide Digital Internet Banking";

        return $message;
    }

    function bfp_handle_vote($chatId, $callbackData) {
        $parts = explode('_', (string)$callbackData);

        if (count($parts) !== 3) {
            return [
                'ok' => false,
                'message' => 'This customer feedback request is currently unavailable.'
            ];
        }

        $pollId = (int)$parts[1];
        $optionId = (int)$parts[2];

        if ($pollId <= 0 || $optionId <= 0) {
            return [
                'ok' => false,
                'message' => 'This customer feedback request is currently unavailable.'
            ];
        }

        $user = bfp_get_user_by_chat_id($chatId);
        if (!$user) {
            return [
                'ok' => false,
                'message' => 'This customer feedback request is currently unavailable.'
            ];
        }

        $pollCheck = bfp_get_active_poll($pollId);
        if (!$pollCheck['ok']) {
            if ($pollCheck['reason'] === 'expired') {
                return [
                    'ok' => false,
                    'message' => 'This customer feedback request has expired and is no longer open for responses. Thank you for your interest.'
                ];
            }
            if ($pollCheck['reason'] === 'closed') {
                return [
                    'ok' => false,
                    'message' => 'This customer feedback request has been closed and is no longer accepting responses. Thank you for your interest.'
                ];
            }
            return [
                'ok' => false,
                'message' => 'This customer feedback request is currently unavailable.'
            ];
        }

        $poll = $pollCheck['poll'];

        $option = bfp_get_poll_option($pollId, $optionId);
        if (!$option) {
            return [
                'ok' => false,
                'message' => 'The selected response option is not valid. Please try again.'
            ];
        }

        if (bfp_already_voted($pollId, (int)$user['id'])) {
            return [
                'ok' => false,
                'message' => 'Your response has already been received and recorded successfully for this customer feedback request. Thank you for your participation.'
            ];
        }

        $save = bfp_save_vote($pollId, $optionId, (int)$user['id'], $chatId);
        if (!$save['ok']) {
            return [
                'ok' => false,
                'message' => 'Unable to record your response at the moment. Please try again.'
            ];
        }

        bfp_mark_notification_clicked($pollId, (int)$user['id']);

        $options = bfp_get_poll_results_summary($pollId);
        $display = bfp_build_display_result_rows($options);
        $resultMessage = bfp_build_result_message((string)$poll['poll_title'], $display['rows'], (int)$display['total_display_votes']);

        $allowComment = !empty($poll['allow_comment']) ? 1 : 0;

        if ($allowComment === 1) {
            bfp_set_pending_comment_state($chatId, $pollId, (int)$user['id']);

            return [
                'ok' => true,
                'message' => "✅ Thank you. Your feedback has been recorded successfully.",
                'result_message' => $resultMessage,
                'comment_message' => "Would you like to share an additional comment regarding this feedback request?\n\nPlease send your comment as a new message.\n\nIf you do not wish to add a comment, reply with: skip",
                'awaiting_comment' => true
            ];
        }

        return [
            'ok' => true,
            'message' => "✅ Thank you. Your feedback has been recorded successfully.",
            'result_message' => $resultMessage,
            'comment_message' => '',
            'awaiting_comment' => false
        ];
    }

    function bfp_handle_comment_message($chatId, $messageText) {
        $state = bfp_get_pending_comment_state($chatId);

        if (!$state) {
            return [
                'handled' => false,
                'message' => ''
            ];
        }

        $pollId = isset($state['poll_id']) ? (int)$state['poll_id'] : 0;
        $userId = isset($state['user_id']) ? (int)$state['user_id'] : 0;
        $text = trim((string)$messageText);

        if ($pollId <= 0 || $userId <= 0) {
            bfp_clear_pending_comment_state($chatId);
            return [
                'handled' => true,
                'message' => 'Comment session expired. Please vote again if needed.'
            ];
        }

        if ($text === '') {
            return [
                'handled' => true,
                'message' => 'Please send your comment as a text message, or reply with: skip'
            ];
        }

        if (mb_strtolower($text, 'UTF-8') === 'skip') {
            bfp_clear_pending_comment_state($chatId);
            return [
                'handled' => true,
                'message' => 'Thank you. Your vote has been saved without an additional comment.'
            ];
        }

        $vote = bfp_get_vote_row($pollId, $userId);
        if (!$vote) {
            bfp_clear_pending_comment_state($chatId);
            return [
                'handled' => true,
                'message' => 'Your vote record could not be found. Please vote again if needed.'
            ];
        }

        $save = bfp_save_comment($pollId, $userId, $text);
        bfp_clear_pending_comment_state($chatId);

        if (!$save['ok']) {
            return [
                'handled' => true,
                'message' => 'Your vote was saved, but your comment could not be stored at the moment.'
            ];
        }

        return [
            'handled' => true,
            'message' => '✅ Thank you. Your additional comment has been recorded successfully.'
        ];
    }

    function bfp_is_waiting_for_comment($chatId) {
        return bfp_get_pending_comment_state($chatId) ? true : false;
    }
}
?>