""" Project module.

This module contains classes for manipulating Kes projects and activities.
"""


from functools import cached_property
from typing import List, Optional, ByteString
from uuid import UUID

from kes.proto.project_pb2 import ReadActivitiesReply, ReadActivitiesRequest, DownloadReportRequest
from kes.proto.project_pb2_grpc import ProjectDetailStub
from kes.proto.table_pb2_grpc import TableStub
from kes.table import RowType, Table, TableDef


class Activity:
    """A Kes activity.

    An activity is the execution of a template. This class is a factory to build
    tables for this activity.
    """

    _id: UUID
    _description: str
    _stub: TableStub
    _project_stub: ProjectDetailStub

    def __init__(self, stub: TableStub, id: UUID, description: str, project_stub: ProjectDetailStub):
        self._id = id
        self._stub = stub
        self._description = description
        self._project_stub = project_stub

    def build_table(self, table_def: TableDef[RowType]) -> Table[RowType]:
        """ Create a table for this activity.

        Args:
            table_def (TableDef):
                A definition of the table to create. Table definitions are generated by the script scaffolder.

        Returns:
            A table.
        """
        return Table[RowType](
            self._stub,
            self._id,
            table_def.row_type,
            table_def.asset_type_id,
            table_def.property_map
        )

    def download_report(self) -> Optional[ByteString]:
        """ Download Report for the activity.

        Returns:
            Activity Report.
        """
        reportData = bytearray()
        request = DownloadReportRequest(activityId=str(self._id))
        streamingReply = self._project_stub.downloadReport(request)

        for reply in streamingReply:
            reportData += reply.chunk

        return reportData

    @property
    def id(self) -> UUID:
        """uuid: id of the activity."""
        return self._id

    @property
    def description(self) -> str:
        """str: description of the activity."""
        return self._description


class Project:
    """A Kes project.

    An project can contain multiple activities.
    """
    _project_id: UUID
    _project_name: str
    _project_number: str
    _master_project_id: str
    _table_stub: TableStub
    _project_stub: ProjectDetailStub

    def __init__(self, project_id: UUID, project_name: str, project_number: str, master_project_id: str,
                 table_stub: TableStub, project_stub: ProjectDetailStub):
        self._project_id = project_id
        self._project_name = project_name
        self._project_number = project_number
        self._master_project_id = master_project_id
        self._table_stub = table_stub
        self._project_stub = project_stub
        self._inspections = None

    @cached_property
    def activities(self) -> List[Activity]:
        """List: The activities of the project."""
        request = ReadActivitiesRequest(projectId=str(self._project_id))
        reply: ReadActivitiesReply = self._project_stub.readActivities(request)

        activities: List[Activity] = []
        for pb_activity in reply.activities:
            activity = Activity(self._table_stub, UUID(pb_activity.id), pb_activity.description)
            activities.append(activity)

        return activities
