# v7

from __future__ import annotations

from typing import Any
from dataclasses import dataclass
from pathlib import Path

from PySide6.QtCore import (
    QAbstractTableModel,
    QModelIndex,
    Qt,
)



@dataclass(slots=True)
class ProfileContext:
    name: str

    root: Path

    storage_path: Path
    cache_path: Path
    downloads_path: Path

    plugins_path: Path
    themes_path: Path
    extensions_path: Path

    profile_db: Path
    permissions_db: Path
    network_db: Path

class NetworkTableModel(
    QAbstractTableModel
):
    HEADERS = (
        "Method",
        "Status",
        "Host",
        "URL",
        "Type",
        "Duration",
        "Timestamp",
    )

    def __init__(
        self,
        parent=None,
    ):
        super().__init__(
            parent
        )

        self._rows: list[
            dict[str, Any]
        ] = []

    def set_rows(
        self,
        rows,
    ) -> None:
        self.beginResetModel()

        self._rows = [
            dict(row)
            for row in rows
        ]

        self.endResetModel()

    def append_row(
        self,
        row: dict,
    ) -> None:
        position = len(
            self._rows
        )

        self.beginInsertRows(
            QModelIndex(),
            position,
            position,
        )

        self._rows.append(
            row
        )

        self.endInsertRows()

    def rowCount(
        self,
        parent=QModelIndex(),
    ) -> int:
        return 0 if parent.isValid() else len(
            self._rows
        )

    def columnCount(
        self,
        parent=QModelIndex(),
    ) -> int:
        return 0 if parent.isValid() else len(
            self.HEADERS
        )

    def headerData(
        self,
        section,
        orientation,
        role,
    ):
        if (
            role
            != Qt.ItemDataRole.DisplayRole
        ):
            return None

        if (
            orientation
            == Qt.Orientation.Horizontal
        ):
            if (
                0
                <= section
                < len(
                    self.HEADERS
                )
            ):
                return self.HEADERS[
                    section
                ]

        return str(
            section + 1
        )

    def data(
        self,
        index,
        role,
    ):
        if (
            not index.isValid()
            or role
            != Qt.ItemDataRole.DisplayRole
        ):
            return None

        row = self._rows[
            index.row()
        ]

        match index.column():
            case 0:
                return row.get(
                    "method",
                    "",
                )

            case 1:
                return row.get(
                    "status_code",
                    row.get(
                        "status",
                        "",
                    ),
                )

            case 2:
                return row.get(
                    "host",
                    "",
                )

            case 3:
                return row.get(
                    "url",
                    "",
                )

            case 4:
                return row.get(
                    "resource_type",
                    "",
                )

            case 5:
                duration = row.get(
                    "duration_ms"
                )

                if duration is None:
                    return ""

                try:
                    return (
                        f"{float(duration):.2f}"
                    )
                except (
                    TypeError,
                    ValueError,
                ):
                    return ""

            case 6:
                return row.get(
                    "timestamp",
                    "",
                )

        return None

    def row(
        self,
        position: int,
    ) -> dict:
        return self._rows[
            position
        ]


class ProfileModel(
    QAbstractTableModel
):
    HEADERS = (
        "Profile",
    )

    def __init__(
        self,
        parent=None,
    ):
        super().__init__(
            parent
        )

        self._profiles: list[
            str
        ] = []

    def set_profiles(
        self,
        profiles: list[str],
    ):
        self.beginResetModel()

        self._profiles = sorted(
            profiles
        )

        self.endResetModel()

    def rowCount(
        self,
        parent=QModelIndex(),
    ):
        return 0 if parent.isValid() else len(
            self._profiles
        )

    def columnCount(
        self,
        parent=QModelIndex(),
    ):
        return 0 if parent.isValid() else 1

    def headerData(
        self,
        section,
        orientation,
        role,
    ):
        if (
            role
            != Qt.ItemDataRole.DisplayRole
        ):
            return None

        if (
            orientation
            == Qt.Orientation.Horizontal
        ):
            return self.HEADERS[
                section
            ]

        return None

    def data(
        self,
        index,
        role,
    ):
        if (
            not index.isValid()
            or role
            != Qt.ItemDataRole.DisplayRole
        ):
            return None

        return self._profiles[
            index.row()
        ]


class AddonModel(
    QAbstractTableModel
):
    HEADERS = (
        "Name",
        "Enabled",
        "Type",
    )

    def __init__(
        self,
        parent=None,
    ):
        super().__init__(
            parent
        )

        self._addons: list[
            dict
        ] = []

    def set_addons(
        self,
        addons: list[dict],
    ):
        self.beginResetModel()

        self._addons = list(
            addons
        )

        self.endResetModel()

    def rowCount(
        self,
        parent=QModelIndex(),
    ):
        return 0 if parent.isValid() else len(
            self._addons
        )

    def columnCount(
        self,
        parent=QModelIndex(),
    ):
        return 0 if parent.isValid() else 3

    def headerData(
        self,
        section,
        orientation,
        role,
    ):
        if (
            role
            != Qt.ItemDataRole.DisplayRole
        ):
            return None

        if (
            orientation
            == Qt.Orientation.Horizontal
        ):
            return self.HEADERS[
                section
            ]

        return None

    def data(
        self,
        index,
        role,
    ):
        if (
            not index.isValid()
            or role
            != Qt.ItemDataRole.DisplayRole
        ):
            return None

        addon = self._addons[
            index.row()
        ]

        match index.column():
            case 0:
                return addon.get(
                    "name",
                    "",
                )

            case 1:
                return (
                    "Yes"
                    if addon.get(
                        "enabled",
                        True,
                    )
                    else "No"
                )

            case 2:
                return addon.get(
                    "type",
                    "",
                )

        return None


class PluginTableModel(
    QAbstractTableModel
):
    HEADERS = (
        "Enabled",
        "Name",
        "Version",
        "Author",
        "Status",
    )

    def __init__(
        self,
        parent=None,
    ):
        super().__init__(
            parent
        )

        self._plugins = []

    def set_plugins(
        self,
        plugins,
    ):
        self.beginResetModel()

        self._plugins = [
            dict(plugin)
            for plugin in plugins
        ]

        self.endResetModel()

    def rowCount(
        self,
        parent=QModelIndex(),
    ):
        return 0 if parent.isValid() else len(
            self._plugins
        )

    def columnCount(
        self,
        parent=QModelIndex(),
    ):
        return 0 if parent.isValid() else 5

    def headerData(
        self,
        section,
        orientation,
        role,
    ):
        if (
            role
            != Qt.ItemDataRole.DisplayRole
        ):
            return None

        if (
            orientation
            == Qt.Orientation.Horizontal
        ):
            return self.HEADERS[
                section
            ]

        return None

    def data(
        self,
        index,
        role,
    ):
        if (
            not index.isValid()
            or role
            != Qt.ItemDataRole.DisplayRole
        ):
            return None

        plugin = self._plugins[
            index.row()
        ]

        match index.column():
            case 0:
                return (
                    "Yes"
                    if plugin.get(
                        "enabled",
                        True,
                    )
                    else "No"
                )

            case 1:
                return plugin.get(
                    "name",
                    "",
                )

            case 2:
                return plugin.get(
                    "version",
                    "",
                )

            case 3:
                return plugin.get(
                    "author",
                    "",
                )

            case 4:
                return plugin.get(
                    "status",
                    "Loaded",
                )

        return None

    def row(
        self,
        position: int,
    ) -> dict:
        return self._plugins[
            position
        ]


class PluginLogTableModel(
    QAbstractTableModel
):
    HEADERS = (
        "Time",
        "Plugin",
        "Level",
        "Message",
    )

    def __init__(
        self,
        parent=None,
    ):
        super().__init__(
            parent
        )

        self._rows = []

    def set_rows(
        self,
        rows,
    ):
        self.beginResetModel()

        self._rows = [
            dict(row)
            for row in rows
        ]

        self.endResetModel()

    def rowCount(
        self,
        parent=QModelIndex(),
    ):
        return 0 if parent.isValid() else len(
            self._rows
        )

    def columnCount(
        self,
        parent=QModelIndex(),
    ):
        return 0 if parent.isValid() else 4

    def headerData(
        self,
        section,
        orientation,
        role,
    ):
        if (
            role
            != Qt.ItemDataRole.DisplayRole
        ):
            return None

        if (
            orientation
            == Qt.Orientation.Horizontal
        ):
            return self.HEADERS[
                section
            ]

        return None

    def data(
        self,
        index,
        role,
    ):
        if (
            not index.isValid()
            or role
            != Qt.ItemDataRole.DisplayRole
        ):
            return None

        row = self._rows[
            index.row()
        ]

        match index.column():
            case 0:
                return row.get(
                    "created_at",
                    "",
                )

            case 1:
                return row.get(
                    "plugin_name",
                    "",
                )

            case 2:
                return row.get(
                    "level",
                    "",
                )

            case 3:
                return row.get(
                    "message",
                    "",
                )

        return None


class PluginCrashTableModel(
    QAbstractTableModel
):
    HEADERS = (
        "Time",
        "Plugin",
        "Error",
    )

    def __init__(
        self,
        parent=None,
    ):
        super().__init__(
            parent
        )

        self._rows = []

    def set_rows(
        self,
        rows,
    ):
        self.beginResetModel()

        self._rows = [
            dict(row)
            for row in rows
        ]

        self.endResetModel()

    def rowCount(
        self,
        parent=QModelIndex(),
    ):
        return 0 if parent.isValid() else len(
            self._rows
        )

    def columnCount(
        self,
        parent=QModelIndex(),
    ):
        return 0 if parent.isValid() else 3

    def headerData(
        self,
        section,
        orientation,
        role,
    ):
        if (
            role
            != Qt.ItemDataRole.DisplayRole
        ):
            return None

        if (
            orientation
            == Qt.Orientation.Horizontal
        ):
            return self.HEADERS[
                section
            ]

        return None

    def data(
        self,
        index,
        role,
    ):
        if (
            not index.isValid()
            or role
            != Qt.ItemDataRole.DisplayRole
        ):
            return None

        row = self._rows[
            index.row()
        ]

        match index.column():
            case 0:
                return row.get(
                    "created_at",
                    "",
                )

            case 1:
                return row.get(
                    "plugin_name",
                    "",
                )

            case 2:
                return row.get(
                    "error",
                    "",
                )

        return None
