import re
import ast
from PyQt5.QtWidgets import (
    QWidget, QVBoxLayout, QLabel, QFrame,
    QHBoxLayout, QTreeWidget, QTreeWidgetItem, QHeaderView, 
    QListWidget, QListWidgetItem, QTabWidget, QSizePolicy,
    QListView, QAbstractItemView, QTableWidget, QTableWidgetItem,
    QStackedWidget, QComboBox, QGridLayout
)
from PyQt5.QtCore import Qt, QRectF
from PyQt5.QtGui import QColor, QFont, QBrush, QPainter, QPen, QPainterPath

from gui.assets.theme.styler import current_theme

from gui.core.history_model import HistoryLogModel, HistoryLogDelegate, HistoryItem, HistoryListView
from gui.widgets.percepts_table import PerceptsTableWidget
from gui.widgets.help_button import HelpButton


class StatusCard(QFrame):
    def __init__(self, parent=None):
        super().__init__(parent)
        self._data = {
            'cycle': '-',
            'action': '-',
            'event': '-',
            'intentions': '-'
        }
        
        self.setMinimumHeight(120)
        self.setMaximumHeight(140)
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
    
    def set_data(self, cycle, action, event, intentions):
        self._data = {
            'cycle': str(cycle),
            'action': str(action) if action else '-',
            'event': str(event) if event else '-',
            'intentions': str(intentions)
        }
        self.update()
    
    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        
        rect = self.rect()
        
        bg_color = QColor(current_theme.get('background_secondary', '#1F2937'))
        border_color = QColor(current_theme.get('background_tertiary', '#4B5563'))
        text_primary = QColor(current_theme.get('text_primary', '#F9FAFB'))
        text_secondary = QColor(current_theme.get('text_secondary', '#9CA3AF'))
        accent = QColor(current_theme.get('interactive_primary', '#3B82F6'))
        
        bg_rect = QRectF(rect).adjusted(1, 1, -1, -1)
        path = QPainterPath()
        path.addRoundedRect(bg_rect, 10, 10)
        
        painter.setPen(QPen(border_color, 1))
        painter.setBrush(QBrush(bg_color))
        painter.drawPath(path)
        
        accent_rect = QRectF(bg_rect.left() + 4, bg_rect.top() + 12, 4, bg_rect.height() - 24)
        accent_path = QPainterPath()
        accent_path.addRoundedRect(accent_rect, 2, 2)
        painter.setPen(Qt.NoPen)
        painter.setBrush(QBrush(accent))
        painter.drawPath(accent_path)
        
        content_left = bg_rect.left() + 20
        content_width = bg_rect.width() - 32
        col_width = content_width / 2
        row_height = (bg_rect.height() - 24) / 2
        
        label_font = QFont("Segoe UI", 9)
        value_font = QFont("Segoe UI", 11, QFont.Bold)
        
        items = [
            ('Cycle', self._data['cycle'], 0, 0),
            ('Intentions', self._data['intentions'], 0, 1),
            ('Current Action', self._data['action'], 1, 0),
            ('Processing Event', self._data['event'], 1, 1),
        ]
        
        for label, value, row, col in items:
            x = content_left + col * col_width
            y = bg_rect.top() + 12 + row * row_height
            
            painter.setFont(label_font)
            painter.setPen(text_secondary)
            painter.drawText(QRectF(x, y, col_width - 10, 16), 
                           Qt.AlignLeft | Qt.AlignVCenter, label)
            
            painter.setFont(value_font)
            painter.setPen(text_primary)
            fm = painter.fontMetrics()
            truncated = fm.elidedText(str(value), Qt.ElideRight, int(col_width - 20))
            painter.drawText(QRectF(x, y + 18, col_width - 10, 24), 
                           Qt.AlignLeft | Qt.AlignVCenter, truncated)
        
        painter.end()


class MiniInfoCard(QFrame):
    def __init__(self, title, accent_color=None, parent=None):
        super().__init__(parent)
        self._title = title
        self._items = []
        self._accent_color = accent_color or "#3B82F6"
        
        self.setMinimumHeight(80)
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
    
    def set_items(self, items):
        self._items = items if items else []
        self.update()
    
    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        
        rect = self.rect()
        
        bg_color = QColor(current_theme.get('background_secondary', '#1F2937'))
        border_color = QColor(current_theme.get('background_tertiary', '#4B5563'))
        text_primary = QColor(current_theme.get('text_primary', '#F9FAFB'))
        text_secondary = QColor(current_theme.get('text_secondary', '#9CA3AF'))
        accent = QColor(self._accent_color)
        
        bg_rect = QRectF(rect).adjusted(1, 1, -1, -1)
        path = QPainterPath()
        path.addRoundedRect(bg_rect, 8, 8)
        
        painter.setPen(QPen(border_color, 1))
        painter.setBrush(QBrush(bg_color))
        painter.drawPath(path)
        
        accent_rect = QRectF(bg_rect.left() + 4, bg_rect.top() + 8, 3, bg_rect.height() - 16)
        accent_path = QPainterPath()
        accent_path.addRoundedRect(accent_rect, 1.5, 1.5)
        painter.setPen(Qt.NoPen)
        painter.setBrush(QBrush(accent))
        painter.drawPath(accent_path)
        
        content_left = bg_rect.left() + 16
        
        title_font = QFont("Segoe UI", 9)
        painter.setFont(title_font)
        painter.setPen(text_secondary)
        count_text = f"{self._title} ({len(self._items)})"
        painter.drawText(QRectF(content_left, bg_rect.top() + 8, bg_rect.width() - 24, 18), 
                        Qt.AlignLeft | Qt.AlignVCenter, count_text)
        
        value_font = QFont("Segoe UI", 10)
        painter.setFont(value_font)
        painter.setPen(text_primary)
        
        if self._items:
            items_text = ", ".join(self._items[:5])
            if len(self._items) > 5:
                items_text += f" (+{len(self._items) - 5})"
        else:
            items_text = "None"
            painter.setPen(text_secondary)
        
        fm = painter.fontMetrics()
        truncated = fm.elidedText(items_text, Qt.ElideRight, int(bg_rect.width() - 30))
        painter.drawText(QRectF(content_left, bg_rect.top() + 32, bg_rect.width() - 24, 24), 
                        Qt.AlignLeft | Qt.AlignVCenter, truncated)
        
        painter.end()


class LearningInfoCard(QFrame):
    def __init__(self, parent=None):
        super().__init__(parent)
        self._environment = "-"
        self._status = "-"
        self._status_color = "#9CA3AF"
        
        self.setMinimumHeight(80)
        self.setMaximumHeight(90)
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
    
    def set_data(self, environment, status, is_complete):
        self._environment = environment
        self._status = status
        
        if is_complete:
            self._status_color = current_theme.get('success', '#10B981')
        else:
            self._status_color = current_theme.get('warning', '#F59E0B')
        
        self.update()
    
    def clear(self):
        self._environment = "-"
        self._status = "-"
        self._status_color = "#9CA3AF"
        self.update()
    
    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        
        rect = self.rect()
        
        bg_color = QColor(current_theme.get('background_secondary', '#1F2937'))
        border_color = QColor(current_theme.get('background_tertiary', '#4B5563'))
        text_primary = QColor(current_theme.get('text_primary', '#F9FAFB'))
        text_secondary = QColor(current_theme.get('text_secondary', '#9CA3AF'))
        accent = QColor(current_theme.get('interactive_primary', '#3B82F6'))
        
        bg_rect = QRectF(rect).adjusted(1, 1, -1, -1)
        path = QPainterPath()
        path.addRoundedRect(bg_rect, 8, 8)
        
        painter.setPen(QPen(border_color, 1))
        painter.setBrush(QBrush(bg_color))
        painter.drawPath(path)
        
        accent_rect = QRectF(bg_rect.left() + 4, bg_rect.top() + 10, 4, bg_rect.height() - 20)
        accent_path = QPainterPath()
        accent_path.addRoundedRect(accent_rect, 2, 2)
        painter.setPen(Qt.NoPen)
        painter.setBrush(QBrush(accent))
        painter.drawPath(accent_path)
        
        content_left = bg_rect.left() + 18
        content_width = bg_rect.width() - 28
        col_width = content_width / 2
        
        label_font = QFont("Segoe UI", 9)
        value_font = QFont("Segoe UI", 11)
        
        y_top = bg_rect.top() + 16
        
        painter.setFont(label_font)
        painter.setPen(text_secondary)
        painter.drawText(QRectF(content_left, y_top, col_width, 16), 
                        Qt.AlignLeft | Qt.AlignVCenter, "Environment")
        
        painter.setFont(value_font)
        painter.setPen(text_primary)
        painter.drawText(QRectF(content_left, y_top + 20, col_width - 10, 24), 
                        Qt.AlignLeft | Qt.AlignVCenter, self._environment)
        
        col2_left = content_left + col_width
        painter.setFont(label_font)
        painter.setPen(text_secondary)
        painter.drawText(QRectF(col2_left, y_top, col_width, 16), 
                        Qt.AlignLeft | Qt.AlignVCenter, "Training Status")
        
        painter.setFont(value_font)
        painter.setPen(QColor(self._status_color))
        painter.drawText(QRectF(col2_left, y_top + 20, col_width, 24), 
                        Qt.AlignLeft | Qt.AlignVCenter, self._status)
        
        painter.end()


class ModelSelectorCard(QFrame):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setMinimumHeight(70)
        self.setMaximumHeight(80)
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        self._setup_ui()
    
    def _setup_ui(self):
        layout = QHBoxLayout(self)
        layout.setContentsMargins(16, 12, 16, 12)
        layout.setSpacing(16)
        
        label = QLabel("Model")
        label.setFont(QFont("Segoe UI", 10))
        label.setProperty("class", "text-secondary")
        
        self.combo = QComboBox()
        self.combo.setMinimumWidth(250)
        self.combo.setMinimumHeight(36)
        self.combo.setCursor(Qt.PointingHandCursor)
        
        layout.addWidget(label)
        layout.addWidget(self.combo)
        layout.addStretch()
    
    def style_combo(self):
        bg_secondary = current_theme.get('background_secondary', '#1F2937')
        bg_tertiary = current_theme.get('background_tertiary', '#4B5563')
        text_primary = current_theme.get('text_primary', '#F9FAFB')
        interactive = current_theme.get('interactive_primary', '#3B82F6')
        
        self.combo.setStyleSheet(f"""
            QComboBox {{
                background-color: {bg_secondary};
                border: 1px solid {bg_tertiary};
                border-radius: 6px;
                padding: 8px 12px;
                color: {text_primary};
                font-size: 12px;
            }}
            QComboBox:hover {{
                border: 1px solid {interactive};
            }}
            QComboBox::drop-down {{
                border: none;
                padding-right: 10px;
            }}
            QComboBox QAbstractItemView {{
                background-color: {bg_secondary};
                border: 1px solid {bg_tertiary};
                selection-background-color: {interactive};
                color: {text_primary};
            }}
        """)
    
    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        
        rect = self.rect()
        
        bg_color = QColor(current_theme.get('background_secondary', '#1F2937'))
        border_color = QColor(current_theme.get('background_tertiary', '#4B5563'))
        accent = QColor(current_theme.get('interactive_primary', '#3B82F6'))
        
        bg_rect = QRectF(rect).adjusted(1, 1, -1, -1)
        path = QPainterPath()
        path.addRoundedRect(bg_rect, 8, 8)
        
        painter.setPen(QPen(border_color, 1))
        painter.setBrush(QBrush(bg_color))
        painter.drawPath(path)
        
        accent_rect = QRectF(bg_rect.left() + 4, bg_rect.top() + 8, 3, bg_rect.height() - 16)
        accent_path = QPainterPath()
        accent_path.addRoundedRect(accent_rect, 1.5, 1.5)
        painter.setPen(Qt.NoPen)
        painter.setBrush(QBrush(accent))
        painter.drawPath(accent_path)
        
        painter.end()
        
        super().paintEvent(event)


class AgentDetailWindow(QWidget):
    def __init__(self, agent_name, data_model, parent=None):
        super().__init__(parent)
        self.agent_name = agent_name
        self.data_model = data_model
        self.setObjectName("AgentDetailWindow")
        
        self.setWindowTitle(f"Agent's Details: {self.agent_name}")
        self.setGeometry(150, 150, 900, 750) 
        self.setAttribute(Qt.WA_DeleteOnClose) 

        self.last_log_index = 0
        self.last_intention_in_history = None
        self.regex_change = re.compile(r"(Adding|Removing) Info: (Belief|Goal) (.*?)\s+-\s+instant\[.*\]$")

        self.belief_items = []
        self.goal_items = []
        self.intention_items = []

        self.previous_beliefs_set = set()
        self.previous_goals_set = set()
        self.active_beliefs = set()
        self.active_goals = set()
        self.successful_goals = set()
        self.changes_this_cycle = set()

        self.belief_model = HistoryLogModel()
        self.goal_model = HistoryLogModel()
        self.intention_model = HistoryLogModel()

        main_layout = QVBoxLayout(self)
        main_layout.setContentsMargins(15, 15, 15, 15)
        main_layout.setSpacing(10)
        
        title = QLabel(f"Monitoring: {self.agent_name}")
        title.setFont(QFont("Segoe UI", 18, QFont.Bold))
        title.setAlignment(Qt.AlignCenter)
        main_layout.addWidget(title)
        
        tab_widget = QTabWidget()
        main_layout.addWidget(tab_widget)

        tab_widget.addTab(self._create_overview_tab(), "Overview")
        tab_widget.addTab(self._create_mind_tab(), "Agent's Mind")
        tab_widget.addTab(self._create_perception_tab(), "Environment and Channels")
        tab_widget.addTab(self._create_learning_tab(), "Learning")
        
        self.data_model.agent_data_updated.connect(self.on_agent_data_updated)

        self.update_data()

    def update_theme(self):
        for view in [self.belief_view, self.goal_view, self.intention_view]:
            delegate = view.itemDelegate()
            if hasattr(delegate, 'update_theme_colors'):
                delegate.update_theme_colors()
            view.viewport().update()

        if hasattr(self, 'perceptions_table'):
            self.perceptions_table.update_theme()
        
        if hasattr(self, 'status_card'):
            self.status_card.update()
        if hasattr(self, 'env_card'):
            self.env_card.update()
        if hasattr(self, 'ch_card'):
            self.ch_card.update()
        if hasattr(self, 'learning_info_card'):
            self.learning_info_card.update()
        if hasattr(self, 'model_selector_card'):
            self.model_selector_card.style_combo()
            self.model_selector_card.update()
        
        self.repaint()

    def on_agent_data_updated(self, updated_agent_name):
        if updated_agent_name == self.agent_name:
            self.update_data()

    def update_data(self):
        full_history = self.data_model.get_agent_log_history(self.agent_name)
        if not full_history: return
        
        latest_state = full_history[-1]
        self._update_snapshots(latest_state)

        self._update_learning_tab()

        total_logs = len(full_history)
        if total_logs == self.last_log_index: return

        new_logs = full_history[self.last_log_index:]
        self.last_log_index = total_logs
        self._process_new_logs_to_models(new_logs, full_history)

    def _normalize_belief_or_goal(self, item):
        if isinstance(item, dict):
            tipo = item.get('type', '')
            predicate = item.get('predicate', '')
            args = item.get('args', [])
            source = item.get('source', '')
            args_str = ", ".join(map(str, args))
            return f"{tipo}: {predicate}({args_str}) [{source}]"
        return str(item)

    def _get_beliefs_set(self, log):
        beliefs = getattr(log, 'beliefs', []) or []
        return {self._normalize_belief_or_goal(b) for b in beliefs}

    def _get_goals_set(self, log):
        goals = getattr(log, 'goals', []) or []
        return {self._normalize_belief_or_goal(g) for g in goals}

    def _process_new_logs_to_models(self, new_logs, full_history):
        items_added = False
        
        for i, log in enumerate(new_logs):
            desc = log.desc
            timestamp = log.system_time
            cycle = log.cycle
            
            current_beliefs = self._get_beliefs_set(log)
            current_goals = self._get_goals_set(log)
            
            def record_change(item_type, msg_type, content):
                change_key = (cycle, item_type, msg_type, content)
                if change_key in self.changes_this_cycle:
                    return False
                self.changes_this_cycle.add(change_key)
                return True
            
            gained_beliefs = current_beliefs - self.previous_beliefs_set
            for belief_str in gained_beliefs:
                if belief_str not in self.active_beliefs:
                    if record_change('belief', 'GAIN', belief_str):
                        item = HistoryItem('GAIN', belief_str, timestamp, cycle)
                        self.belief_items.append(item)
                        self.active_beliefs.add(belief_str)
                        items_added = True
            
            lost_beliefs = self.previous_beliefs_set - current_beliefs
            for belief_str in lost_beliefs:
                if belief_str in self.active_beliefs:
                    if record_change('belief', 'LOSE', belief_str):
                        item = HistoryItem('LOSE', belief_str, timestamp, cycle)
                        self.belief_items.append(item)
                        self.active_beliefs.discard(belief_str)
                        items_added = True
            
            gained_goals = current_goals - self.previous_goals_set
            for goal_str in gained_goals:
                if goal_str not in self.active_goals:
                    if record_change('goal', 'GAIN', goal_str):
                        item = HistoryItem('GAIN', goal_str, timestamp, cycle)
                        self.goal_items.append(item)
                        self.active_goals.add(goal_str)
                        items_added = True
            
            lost_goals = self.previous_goals_set - current_goals
            for goal_str in lost_goals:
                if goal_str in self.active_goals:
                    if record_change('goal', 'LOSE', goal_str):
                        item = HistoryItem('LOSE', goal_str, timestamp, cycle)
                        self.goal_items.append(item)
                        self.active_goals.discard(goal_str)
                        items_added = True
            
            match = self.regex_change.match(desc)
            if not match:
                match = self.regex_change.search(desc)
            
            if match:
                action_type = match.group(1)
                item_type = match.group(2)
                content = match.group(3).strip()
                msg_type = 'GAIN' if action_type == "Adding" else 'LOSE'
                normalized_content = f"{item_type} {content}"
                
                if item_type == 'Belief':
                    if msg_type == 'GAIN' and normalized_content not in self.active_beliefs:
                        if record_change('belief', 'GAIN', normalized_content):
                            item = HistoryItem(msg_type, normalized_content, timestamp, cycle)
                            self.belief_items.append(item)
                            self.active_beliefs.add(normalized_content)
                            items_added = True
                    elif msg_type == 'LOSE' and normalized_content in self.active_beliefs:
                        if record_change('belief', 'LOSE', normalized_content):
                            item = HistoryItem(msg_type, normalized_content, timestamp, cycle)
                            self.belief_items.append(item)
                            self.active_beliefs.discard(normalized_content)
                            items_added = True
                elif item_type == 'Goal':
                    if msg_type == 'GAIN' and normalized_content not in self.active_goals:
                        if record_change('goal', 'GAIN', normalized_content):
                            item = HistoryItem(msg_type, normalized_content, timestamp, cycle)
                            self.goal_items.append(item)
                            self.active_goals.add(normalized_content)
                            items_added = True
                    elif msg_type == 'LOSE' and normalized_content in self.active_goals:
                        if record_change('goal', 'LOSE', normalized_content):
                            item = HistoryItem(msg_type, normalized_content, timestamp, cycle)
                            self.goal_items.append(item)
                            self.active_goals.discard(normalized_content)
                            items_added = True
            
            self.previous_beliefs_set = current_beliefs
            self.previous_goals_set = current_goals
            
            for evt in log.events:
                if "success:" in evt and "Goal" in evt:
                    content = evt.replace("success:", "")
                    if content not in self.successful_goals:
                        item = HistoryItem('SUCCESS', content, timestamp, cycle)
                        self.goal_items.append(item)
                        self.successful_goals.add(content)
                        items_added = True

            curr = log.last_intention
            if curr and curr != 'null' and curr != self.last_intention_in_history:
                event_str = log.last_event.replace('gain:', '').replace('lose:', '') if log.last_event else ''
                content_str = f"Trigger: {event_str} | {curr}"
                item = HistoryItem('INTENTION', content_str, timestamp, cycle)
                self.intention_items.append(item)
                self.last_intention_in_history = curr
                items_added = True

        if items_added:
            self.belief_model.set_items(self.belief_items)
            self.goal_model.set_items(self.goal_items)
            self.intention_model.set_items(self.intention_items)
            self._scroll_to_bottom(self.belief_view, self.belief_model)
            self._scroll_to_bottom(self.goal_view, self.goal_model)
            self._scroll_to_bottom(self.intention_view, self.intention_model)
            
            self._update_mind_counters()

    def _scroll_to_bottom(self, view, model):
        if model.rowCount() > 0:
            view.scrollTo(model.index(model.rowCount() - 1, 0), QAbstractItemView.EnsureVisible)

    def _update_snapshots(self, latest_state):
        self.status_card.set_data(
            latest_state.cycle,
            latest_state.action,
            latest_state.last_event,
            len(latest_state.running_intentions)
        )
        
        self._update_list_widget(self.running_intentions_list, latest_state.running_intentions)
        self._update_list_widget(self.current_beliefs_list, latest_state.beliefs)
        self._update_list_widget(self.current_goals_list, latest_state.goals)
        
        self.perceptions_table.set_percepts(latest_state.perceptions)
        
        self.env_card.set_items(latest_state.envs)
        self.ch_card.set_items(latest_state.chs)

    def _create_section_title(self, text):
        title = QLabel(text)
        title.setProperty("class", "h2")
        title.setFont(QFont("Segoe UI", 12, QFont.Bold))
        return title
    
    def _create_section_title_with_counter(self, text):
        container = QWidget()
        layout = QHBoxLayout(container)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(8)
        
        title = QLabel(text)
        title.setProperty("class", "h2")
        title.setFont(QFont("Segoe UI", 12, QFont.Bold))
        
        counter = QLabel("(0)")
        counter.setProperty("class", "text-secondary")
        counter.setFont(QFont("Segoe UI", 11))
        
        layout.addWidget(title)
        layout.addWidget(counter)
        layout.addStretch()
        
        return container, counter
        
    def _create_frame(self):
        frame = QFrame()
        frame.setProperty("class", "card")
        return frame

    def _create_key_value_display(self, parent_layout, key_text):
        layout = QHBoxLayout()
        key_label = QLabel(f"<b>{key_text}</b>")
        key_label.setProperty("class", "detail-key")
        value_label = QLabel("<i>N/A</i>")
        value_label.setWordWrap(True)
        value_label.setProperty("class", "detail-value")
        value_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
        value_label.setMinimumWidth(100)
        layout.addWidget(key_label)
        layout.addStretch()
        layout.addWidget(value_label)
        parent_layout.addLayout(layout)
        return value_label

    def _create_list_display(self, min_height=120):
        list_widget = QListWidget()
        list_widget.setMinimumHeight(min_height)
        list_widget.setFrameShape(QFrame.NoFrame)
        list_widget.setWordWrap(True)
        list_widget.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        list_widget.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel)
        return list_widget

    def _create_log_list_view(self, model, min_height=150):
        view = HistoryListView()
        view.setModel(model)
        
        delegate = HistoryLogDelegate(view, current_theme)
        view.setItemDelegate(delegate)
        
        view.setStyleSheet("QListView { font-size: 13pt; font-family: Arial; }")
        view.setUniformItemSizes(False)
        view.setWordWrap(False)
        view.setAlternatingRowColors(False)
        view.setSelectionMode(QAbstractItemView.ExtendedSelection)
        view.setMinimumHeight(min_height)
        view.setVerticalScrollMode(QAbstractItemView.ScrollPerPixel)
        view.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        view.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel)
        view.setFrameShape(QFrame.NoFrame)
        
        return view
        
    def _create_tree_display(self, headers):
        tree = QTreeWidget()
        tree.setHeaderLabels(headers)
        tree.header().setSectionResizeMode(0, QHeaderView.ResizeToContents)
        if len(headers) > 1:
            tree.header().setSectionResizeMode(1, QHeaderView.ResizeToContents)
        tree.header().setStretchLastSection(False)
        tree.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        tree.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        tree.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel)
        return tree

    def _create_overview_tab(self):
        tab = QWidget()
        layout = QHBoxLayout(tab) 
        layout.setContentsMargins(15, 15, 15, 15)
        layout.setSpacing(15)

        left_col_layout = QVBoxLayout()
        left_col_layout.setSpacing(12)
        
        left_col_layout.addWidget(self._create_section_title("Real Time Status"))
        
        self.status_card = StatusCard()
        left_col_layout.addWidget(self.status_card)
        
        left_col_layout.addWidget(self._create_section_title("Running Intentions"))
        
        intentions_frame = self._create_frame()
        intentions_layout = QVBoxLayout(intentions_frame)
        intentions_layout.setContentsMargins(12, 12, 12, 12)
        self.running_intentions_list = self._create_list_display(min_height=150)
        intentions_layout.addWidget(self.running_intentions_list)
        left_col_layout.addWidget(intentions_frame)
        
        left_col_layout.addStretch()
        layout.addLayout(left_col_layout)

        right_col_layout = QVBoxLayout()
        right_col_layout.setSpacing(12)
        
        right_col_layout.addWidget(self._create_section_title("Current Beliefs"))
        beliefs_frame = self._create_frame()
        beliefs_layout = QVBoxLayout(beliefs_frame)
        beliefs_layout.setContentsMargins(12, 12, 12, 12)
        self.current_beliefs_list = self._create_list_display()
        beliefs_layout.addWidget(self.current_beliefs_list)
        right_col_layout.addWidget(beliefs_frame)
        
        right_col_layout.addWidget(self._create_section_title("Current Goals"))
        goals_frame = self._create_frame()
        goals_layout = QVBoxLayout(goals_frame)
        goals_layout.setContentsMargins(12, 12, 12, 12)
        self.current_goals_list = self._create_list_display()
        goals_layout.addWidget(self.current_goals_list)
        right_col_layout.addWidget(goals_frame)
        
        right_col_layout.addStretch()
        layout.addLayout(right_col_layout)

        return tab

    def _create_mind_tab(self):
        tab = QWidget()
        main_layout = QVBoxLayout(tab) 
        main_layout.setSpacing(15)
        main_layout.setContentsMargins(15, 15, 15, 15)

        top_layout = QHBoxLayout()
        top_layout.setSpacing(15)
        
        belief_layout = QVBoxLayout()
        belief_header, self.belief_counter = self._create_section_title_with_counter("Beliefs History")
        belief_layout.addWidget(belief_header)
        
        b_frame = self._create_frame()
        b_frame_layout = QVBoxLayout(b_frame)
        b_frame_layout.setContentsMargins(8, 8, 8, 8)
        
        self.belief_view = self._create_log_list_view(self.belief_model)
        b_frame_layout.addWidget(self.belief_view)
        
        belief_layout.addWidget(b_frame)
        top_layout.addLayout(belief_layout)

        goal_layout = QVBoxLayout()
        goal_header, self.goal_counter = self._create_section_title_with_counter("Goals History")
        goal_layout.addWidget(goal_header)
        
        g_frame = self._create_frame()
        g_frame_layout = QVBoxLayout(g_frame)
        g_frame_layout.setContentsMargins(8, 8, 8, 8)
        
        self.goal_view = self._create_log_list_view(self.goal_model)
        g_frame_layout.addWidget(self.goal_view)
        
        goal_layout.addWidget(g_frame)
        top_layout.addLayout(goal_layout)
        
        main_layout.addLayout(top_layout, stretch=1) 

        int_layout = QVBoxLayout()
        int_header, self.intention_counter = self._create_section_title_with_counter("Intentions History")
        int_layout.addWidget(int_header)
        
        i_frame = self._create_frame()
        i_frame_layout = QVBoxLayout(i_frame)
        i_frame_layout.setContentsMargins(8, 8, 8, 8)
        
        self.intention_view = self._create_log_list_view(self.intention_model)
        i_frame_layout.addWidget(self.intention_view)
        
        int_layout.addWidget(i_frame)
        main_layout.addLayout(int_layout, stretch=1) 

        return tab
    
    def _update_mind_counters(self):
        self.belief_counter.setText(f"({len(self.belief_items)})")
        self.goal_counter.setText(f"({len(self.goal_items)})")
        self.intention_counter.setText(f"({len(self.intention_items)})")

    def _create_perception_tab(self):
        tab = QWidget()
        main_layout = QHBoxLayout(tab) 
        main_layout.setSpacing(15)
        main_layout.setContentsMargins(15, 15, 15, 15)

        percept_frame = self._create_frame()
        percept_layout = QVBoxLayout(percept_frame)
        percept_layout.setContentsMargins(16, 16, 16, 16)
        
        percept_title = QLabel("Perceptions")
        percept_title.setFont(QFont("Segoe UI", 12, QFont.Bold))
        percept_layout.addWidget(percept_title)
        
        self.perceptions_table = PerceptsTableWidget()
        percept_layout.addWidget(self.perceptions_table)
        
        main_layout.addWidget(percept_frame, stretch=2) 

        right_frame = self._create_frame()
        right_layout = QVBoxLayout(right_frame)
        right_layout.setContentsMargins(16, 16, 16, 16)
        right_layout.setSpacing(12)
        
        right_title = QLabel("Connections")
        right_title.setFont(QFont("Segoe UI", 12, QFont.Bold))
        right_layout.addWidget(right_title)
        
        self.env_card = MiniInfoCard("Environments", "#10B981")  # green
        self.ch_card = MiniInfoCard("Channels", "#8B5CF6")  # purple
        
        right_layout.addWidget(self.env_card)
        right_layout.addWidget(self.ch_card)
        right_layout.addStretch()
        
        main_layout.addWidget(right_frame, stretch=1) 
        
        return tab

    def _parse_intention_list_for_display(self, intention_str):
        if not isinstance(intention_str, str): return str(intention_str)
        try:
            goal_match = re.search(r"^(gain:Goal.*?\[.*?\])", intention_str)
            plan_match = re.search(r"->\s*([\w\d_]+)\(.*\)", intention_str)
            goal_str = goal_match.group(1) if goal_match else "Complex Goal"
            plan_name = plan_match.group(1) if plan_match else "Complex Plan"
            return f"Plan: {plan_name} | Goal: {goal_str}"
        except Exception: return intention_str 
            
    def _update_list_widget(self, list_widget, items_list):
        list_widget.clear()
        if not items_list:
            item = QListWidgetItem("No items")
            item.setForeground(QColor(current_theme.get('text_disabled', '#888')))
            list_widget.addItem(item)
        else:
            for item_data in items_list:
                display_text = ""
                if list_widget == self.running_intentions_list:
                    display_text = self._parse_intention_list_for_display(item_data)
                elif isinstance(item_data, dict):
                    display_text = self._format_parsed_object_for_display(item_data)
                else:
                    display_text = str(item_data)
                list_widget.addItem(QListWidgetItem(display_text))

    def _format_parsed_object_for_display(self, parsed_item):
        if not isinstance(parsed_item, dict): return str(parsed_item)
        if not parsed_item or parsed_item.get('type') == 'Unknown': return parsed_item.get('raw', str(parsed_item))
        tipo = parsed_item.get('type', '')
        predicate = parsed_item.get('predicate', '')
        args = parsed_item.get('args', [])
        source = parsed_item.get('source', '')
        args_str = ", ".join(map(str, args))
        return f"{tipo}: {predicate}({args_str}) [{source}]"

    def _safe_eval(self, literal):
        try: return ast.literal_eval(literal)
        except (ValueError, SyntaxError): return literal

    def _populate_tree(self, tree, data, parent_item=None):
        if parent_item is None:
            tree.clear()
            parent_item = tree.invisibleRootItem()
        if isinstance(data, str): data = self._safe_eval(data)
        if isinstance(data, dict):
            for key, val in sorted(data.items()):
                key_str = str(self._safe_eval(key))
                child = QTreeWidgetItem([key_str])
                parent_item.addChild(child)
                self._populate_tree(tree, val, child)
        elif isinstance(data, (list, set, tuple)):
            for i, val in enumerate(data):
                child = QTreeWidgetItem([f"Item {i}"])
                parent_item.addChild(child)
                self._populate_tree(tree, val, child)
        else:
            if parent_item.childCount() == 0 and parent_item.text(0) != "root":
                parent_item.setText(1, str(data))
        if parent_item == tree.invisibleRootItem():
            tree.expandAll()
    
    def _create_learning_tab(self):
        tab = QWidget()
        layout = QVBoxLayout(tab)
        layout.setContentsMargins(15, 15, 15, 15)
        layout.setSpacing(12)

        self.learning_status_label = QLabel("No learning models found for this agent")
        self.learning_status_label.setProperty("class", "text-secondary")
        self.learning_status_label.setFont(QFont("Segoe UI", 11))
        layout.addWidget(self.learning_status_label)

        self.model_selector_card = ModelSelectorCard()
        self.model_selector_card.combo.currentTextChanged.connect(self._on_learning_model_selected)
        self.model_selector_card.style_combo()
        layout.addWidget(self.model_selector_card)

        self.learning_info_card = LearningInfoCard()
        layout.addWidget(self.learning_info_card)

        qtable_frame = self._create_frame()
        qtable_layout = QVBoxLayout(qtable_frame)
        qtable_layout.setContentsMargins(16, 16, 16, 16)
        
        qtable_label = QLabel("Q-Table (Policy)")
        qtable_label.setFont(QFont("Segoe UI", 12, QFont.Bold))
        qtable_layout.addWidget(qtable_label)
        
        self.learning_qtable = QTableWidget()
        self.learning_qtable.setObjectName("LearningQTable")
        self.learning_qtable.setAlternatingRowColors(False)
        self.learning_qtable.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.learning_qtable.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.learning_qtable.horizontalHeader().setStretchLastSection(True)
        self.learning_qtable.verticalHeader().setVisible(False)
        self.learning_qtable.setFrameShape(QFrame.NoFrame)
        self._style_table_header(self.learning_qtable)
        qtable_layout.addWidget(self.learning_qtable, 1)
        
        layout.addWidget(qtable_frame, 1)

        self._learning_data = {}
        
        return tab
    
    def _style_table_header(self, table):
        bg_tertiary = current_theme.get('background_tertiary', '#4B5563')
        text_primary = current_theme.get('text_primary', '#F9FAFB')
        interactive = current_theme.get('interactive_primary', '#3B82F6')

        table.horizontalHeader().setStyleSheet(f"""
            QHeaderView::section {{
                background-color: {bg_tertiary};
                color: {text_primary};
                padding: 8px;
                border: none;
                border-bottom: 2px solid {interactive};
                font-weight: bold;
            }}
        """)
    
    def _on_learning_model_selected(self, model_name):
        if not model_name or model_name not in self._learning_data:
            return
        
        model_data = self._learning_data[model_name]
        environment = model_data.get('environment', '-')
        is_complete = model_data.get('training_complete', False)
        status = "Training Complete" if is_complete else "In Progress"
        
        self.learning_info_card.set_data(environment, status, is_complete)
        self._update_learning_qtable(model_data.get('policy', {}))
    
    def _update_learning_qtable(self, policy):
        self.learning_qtable.clear()
        
        if not policy:
            self.learning_qtable.setRowCount(0)
            self.learning_qtable.setColumnCount(1)
            self.learning_qtable.setHorizontalHeaderLabels(["No data"])
            return

        first_state = next(iter(policy.values()))
        num_actions = len(first_state) if isinstance(first_state, list) else 1

        columns = ["State"] + [f"Action {i}" for i in range(num_actions)]
        self.learning_qtable.setColumnCount(len(columns))
        self.learning_qtable.setHorizontalHeaderLabels(columns)

        row_color_1 = QColor(current_theme.get('background_secondary', '#1F2937'))
        row_color_2 = QColor(current_theme.get('background_tertiary', '#4B5563'))
        text_color = QColor(current_theme.get('text_primary', '#F9FAFB'))

        best_value_color = QColor(current_theme.get('success', '#10B981'))
        best_value_color.setAlpha(100)

        self.learning_qtable.setRowCount(len(policy))
        
        for row, (state, values) in enumerate(sorted(policy.items())):
            row_bg = row_color_1 if row % 2 == 0 else row_color_2

            state_item = QTableWidgetItem(str(state))
            state_item.setTextAlignment(Qt.AlignCenter)
            state_item.setBackground(QBrush(row_bg))
            state_item.setForeground(QBrush(text_color))
            self.learning_qtable.setItem(row, 0, state_item)

            if isinstance(values, list):
                max_val = max(values)
                for col, val in enumerate(values):
                    val_item = QTableWidgetItem(f"{val:.4f}")
                    val_item.setTextAlignment(Qt.AlignCenter)
                    val_item.setForeground(QBrush(text_color))

                    if val == max_val:
                        val_item.setBackground(QBrush(best_value_color))
                        val_item.setFont(QFont("Segoe UI", 10, QFont.Bold))
                    else:
                        val_item.setBackground(QBrush(row_bg))
                    
                    self.learning_qtable.setItem(row, col + 1, val_item)
            else:
                val_item = QTableWidgetItem(str(values))
                val_item.setTextAlignment(Qt.AlignCenter)
                val_item.setBackground(QBrush(row_bg))
                val_item.setForeground(QBrush(text_color))
                self.learning_qtable.setItem(row, 1, val_item)

        self.learning_qtable.horizontalHeader().setSectionResizeMode(0, QHeaderView.ResizeToContents)
        for i in range(1, len(columns)):
            self.learning_qtable.horizontalHeader().setSectionResizeMode(i, QHeaderView.Stretch)

        self._style_table_header(self.learning_qtable)
    
    def _update_learning_tab(self):
        self._learning_data = self.data_model.get_learning_for_agent(self.agent_name)
        
        if not self._learning_data:
            self.learning_status_label.setText("No learning models found for this agent")
            self.learning_status_label.setVisible(True)
            self.model_selector_card.combo.clear()
            self.learning_info_card.clear()
            self.learning_qtable.clear()
            self.learning_qtable.setRowCount(0)
            return
        
        self.learning_status_label.setVisible(False)

        current_model = self.model_selector_card.combo.currentText()
        self.model_selector_card.combo.blockSignals(True)
        self.model_selector_card.combo.clear()
        self.model_selector_card.combo.addItems(sorted(self._learning_data.keys()))

        if current_model in self._learning_data:
            self.model_selector_card.combo.setCurrentText(current_model)
        elif self.model_selector_card.combo.count() > 0:
            self.model_selector_card.combo.setCurrentIndex(0)
        
        self.model_selector_card.combo.blockSignals(False)

        if self.model_selector_card.combo.currentText():
            self._on_learning_model_selected(self.model_selector_card.combo.currentText())