import pandas as pd
from typing import List
from mindsdb.integrations.libs.api_handler import APITable
from mindsdb.integrations.utilities.handlers.query_utilities import (
    SELECTQueryParser,
    SELECTQueryExecutor,
)
from mindsdb.utilities import log
from mindsdb_sql_parser import ast
import zenpy

logger = log.getLogger(__name__)


class ZendeskUsersTable(APITable):
    """Zendesk Users Table implementation"""

    def select(self, query: ast.Select) -> pd.DataFrame:
        """Pulls data from the zendesk list users API

        Parameters
        ----------
        query : ast.Select
            Given SQL SELECT query

        Returns
        -------
        pd.DataFrame
            Zendesk users

        Raises
        ------
        ValueError
            If the query contains an unsupported condition
        """

        select_statement_parser = SELECTQueryParser(query, "users", self.get_columns())

        selected_columns, where_conditions, order_by_conditions, result_limit = select_statement_parser.parse_query()

        subset_where_conditions = []
        api_filters = {}
        for op, arg1, arg2 in where_conditions:
            if arg1 in self.get_columns():
                if op != "=":
                    raise NotImplementedError(f"Unknown op: {op}. Only '=' is supported.")
                api_filters[arg1] = arg2
                subset_where_conditions.append([op, arg1, arg2])

        result = self.handler.zen_client.users(**api_filters)
        response = []
        if isinstance(result, zenpy.lib.generator.BaseResultGenerator):
            for user in result:
                response.append(user.to_dict())
        else:
            response.append(result.to_dict())

        df = pd.DataFrame(response, columns=self.get_columns())

        select_statement_executor = SELECTQueryExecutor(
            df, selected_columns, subset_where_conditions, order_by_conditions, result_limit
        )

        df = select_statement_executor.execute_query()

        return df

    def get_columns(self) -> List[str]:
        """Gets all columns to be returned in pandas DataFrame responses

        Returns
        -------
        List[str]
            List of columns
        """

        return [
            "active",
            "alias",
            "chat_only",
            "created_at",
            "custom_role_id",
            "details",
            "email",
            "external_id",
            "id",
            "last_login_at",
            "locale",
            "locale_id",
            "moderator",
            "name",
            "notes",
            "only_private_comments",
            "organization_id",
            "phone",
            "photo",
            "restricted_agent",
            "role",
            "shared",
            "shared_agent",
            "signature",
            "suspended",
            "tags",
            "ticket_restriction",
            "time_zone",
            "two_factor_auth_enabled",
            "updated_at",
            "url",
            "verified",
            "iana_time_zone",
            "shared_phone_number",
            "role_type",
            "default_group_id",
            "report_csv",
        ]


class ZendeskTicketsTable(APITable):
    """Zendesk tickets Table implementation"""

    def select(self, query: ast.Select) -> pd.DataFrame:
        """Pulls data from the zendesk tickets API

        Parameters
        ----------
        query : ast.Select
            Given SQL SELECT query

        Returns
        -------
        pd.DataFrame
            Ticket ID Data

        Raises
        ------
        ValueError
            If the query contains an unsupported condition
        """

        select_statement_parser = SELECTQueryParser(query, "tickets", self.get_columns())

        selected_columns, where_conditions, order_by_conditions, result_limit = select_statement_parser.parse_query()

        subset_where_conditions = []
        api_filters = {}
        for op, arg1, arg2 in where_conditions:
            if arg1 in self.get_columns():
                if op != "=":
                    raise NotImplementedError(f"Unknown op: {op}. Only '=' is supported.")
                api_filters[arg1] = arg2
                subset_where_conditions.append([op, arg1, arg2])

        result = self.handler.zen_client.tickets(**api_filters)
        response = []
        if isinstance(result, zenpy.lib.generator.BaseResultGenerator):
            for ticket in result:
                response.append(ticket.to_dict())
        else:
            response.append(result.to_dict())

        df = pd.DataFrame(response, columns=self.get_columns())

        select_statement_executor = SELECTQueryExecutor(
            df, selected_columns, subset_where_conditions, order_by_conditions, result_limit
        )

        df = select_statement_executor.execute_query()

        return df

    def get_columns(self) -> List[str]:
        """Gets all columns to be returned in pandas DataFrame responses

        Returns
        -------
        List[str]
            List of columns
        """

        return [
            "assignee_id",
            "brand_id",
            "collaborator_ids",
            "created_at",
            "custom_fields",
            "description",
            "due_at",
            "external_id",
            "fields",
            "forum_topic_id",
            "group_id",
            "has_incidents",
            "id",
            "organization_id",
            "priority",
            "problem_id",
            "raw_subject",
            "recipient",
            "requester_id",
            "sharing_agreement_ids",
            "status",
            "subject",
            "submitter_id",
            "tags",
            "type",
            "updated_at",
            "url",
            "generated_timestamp",
            "follower_ids",
            "email_cc_ids",
            "is_public",
            "custom_status_id",
            "followup_ids",
            "ticket_form_id",
            "allow_channelback",
            "allow_attachments",
            "from_messaging_channel",
            "satisfaction_rating.assignee_id",
            "satisfaction_rating.created_at",
            "satisfaction_rating.group_id",
            "satisfaction_rating.id",
            "satisfaction_rating.requester_id",
            "satisfaction_rating.score",
            "satisfaction_rating.ticket_id",
            "satisfaction_rating.updated_at",
            "satisfaction_rating.url",
            "via.channel",
            "via.source.rel",
        ]


class ZendeskTriggersTable(APITable):
    """Zendesk Triggers Table implementation"""

    def select(self, query: ast.Select) -> pd.DataFrame:
        """Pulls data from the zendesk triggers API

        Parameters
        ----------
        query : ast.Select
            Given SQL SELECT query

        Returns
        -------
        pd.DataFrame
            Trigger Data

        Raises
        ------
        ValueError
            If the query contains an unsupported condition
        """

        select_statement_parser = SELECTQueryParser(query, "triggers", self.get_columns())

        selected_columns, where_conditions, order_by_conditions, result_limit = select_statement_parser.parse_query()

        subset_where_conditions = []
        api_filters = {}
        for op, arg1, arg2 in where_conditions:
            if arg1 in self.get_columns():
                if op != "=":
                    raise NotImplementedError(f"Unknown op: {op}. Only '=' is supported.")
                api_filters[arg1] = arg2
                subset_where_conditions.append([op, arg1, arg2])

        result = self.handler.zen_client.triggers(**api_filters)
        response = []
        if isinstance(result, zenpy.lib.generator.BaseResultGenerator):
            for trigger in result:
                response.append(trigger.to_dict())
        else:
            response.append(result.to_dict())

        df = pd.DataFrame(response, columns=self.get_columns())

        select_statement_executor = SELECTQueryExecutor(
            df, selected_columns, subset_where_conditions, order_by_conditions, result_limit
        )

        df = select_statement_executor.execute_query()

        return df

    def get_columns(self) -> List[str]:
        """Gets all columns to be returned in pandas DataFrame responses

        Returns
        -------
        List[str]
            List of columns
        """

        return [
            "actions",
            "active",
            "description",
            "id",
            "position",
            "title",
            "url",
            "updated_at",
            "created_at",
            "default",
            "raw_title",
            "category_id",
            "conditions.all",
            "conditions.any",
        ]


class ZendeskActivitiesTable(APITable):
    """Zendesk Activities Table implementation"""

    def select(self, query: ast.Select) -> pd.DataFrame:
        """Pulls data from the zendesk activities API

        Parameters
        ----------
        query : ast.Select
            Given SQL SELECT query

        Returns
        -------
        pd.DataFrame
            Activity list Data

        Raises
        ------
        ValueError
            If the query contains an unsupported condition
        """

        select_statement_parser = SELECTQueryParser(query, "activities", self.get_columns())

        selected_columns, where_conditions, order_by_conditions, result_limit = select_statement_parser.parse_query()

        subset_where_conditions = []
        api_filters = {}
        for op, arg1, arg2 in where_conditions:
            if arg1 in self.get_columns():
                if op != "=":
                    raise NotImplementedError(f"Unknown op: {op}. Only '=' is supported.")
                api_filters[arg1] = arg2
                subset_where_conditions.append([op, arg1, arg2])

        result = self.handler.zen_client.activities(**api_filters)
        response = []
        if isinstance(result, zenpy.lib.generator.BaseResultGenerator):
            for activity in result:
                response.append(activity.to_dict())
        else:
            response.append(result.to_dict())

        df = pd.DataFrame(response, columns=self.get_columns())

        select_statement_executor = SELECTQueryExecutor(
            df, selected_columns, subset_where_conditions, order_by_conditions, result_limit
        )

        df = select_statement_executor.execute_query()

        return df

    def get_columns(self) -> List[str]:
        """Gets all columns to be returned in pandas DataFrame responses

        Returns
        -------
        List[str]
            List of columns
        """

        return [
            "created_at",
            "id",
            "title",
            "updated_at",
            "url",
            "verb",
            "user_id",
            "actor_id",
            "actor.id",
            "actor.url",
            "actor.name",
            "actor.email",
            "actor.created_at",
            "actor.updated_at",
            "actor.time_zone",
            "actor.iana_time_zone",
            "actor.phone",
            "actor.shared_phone_number",
            "actor.photo",
            "actor.locale_id",
            "actor.locale",
            "actor.organization_id",
            "actor.role",
            "actor.verified",
            "actor.external_id",
            "actor.tags",
            "actor.alias",
            "actor.active",
            "actor.shared",
            "actor.shared_agent",
            "actor.last_login_at",
            "actor.two_factor_auth_enabled",
            "actor.signature",
            "actor.details",
            "actor.notes",
            "actor.role_type",
            "actor.custom_role_id",
            "actor.moderator",
            "actor.ticket_restriction",
            "actor.only_private_comments",
            "actor.restricted_agent",
            "actor.suspended",
            "actor.default_group_id",
            "actor.report_csv",
            "user.active",
            "user.alias",
            "user.chat_only",
            "user.created_at",
            "user.custom_role_id",
            "user.details",
            "user.email",
            "user.external_id",
            "user.id",
            "user.last_login_at",
            "user.locale",
            "user.locale_id",
            "user.moderator",
            "user.name",
            "user.notes",
            "user.only_private_comments",
            "user.organization_id",
            "user.phone",
            "user.photo",
            "user.restricted_agent",
            "user.role",
            "user.shared",
            "user.shared_agent",
            "user.signature",
            "user.suspended",
            "user.tags",
            "user.ticket_restriction",
            "user.time_zone",
            "user.two_factor_auth_enabled",
            "user.updated_at",
            "user.url",
            "user.verified",
            "user.iana_time_zone",
            "user.shared_phone_number",
            "user.role_type",
            "user.default_group_id",
            "user.report_csv",
            "target.active",
            "target.content_type",
            "target.created_at",
            "target.id",
            "target.method",
            "target.password",
            "target.target_url",
            "target.title",
            "target.type",
            "target.url",
            "target.username",
            "target.ticket.assignee_id",
            "target.ticket.brand_id",
            "target.ticket.collaborator_ids",
            "target.ticket.created_at",
            "target.ticket.custom_fields",
            "target.ticket.description",
            "target.ticket.due_at",
            "target.ticket.external_id",
            "target.ticket.fields",
            "target.ticket.forum_topic_id",
            "target.ticket.group_id",
            "target.ticket.has_incidents",
            "target.ticket.id",
            "target.ticket.organization_id",
            "target.ticket.priority",
            "target.ticket.problem_id",
            "target.ticket.raw_subject",
            "target.ticket.recipient",
            "target.ticket.requester_id",
            "target.ticket.satisfaction_rating",
            "target.ticket.sharing_agreement_ids",
            "target.ticket.status",
            "target.ticket.subject",
            "target.ticket.submitter_id",
            "target.ticket.tags",
            "target.ticket.type",
            "target.ticket.updated_at",
            "target.ticket.url",
            "target.ticket.via",
        ]
