from eolymp.atlas import statement_pb2, ProblemServiceClient, StatementServiceClient
from eolymp.atlas.problem_pb2 import Problem
from eolymp.atlas.problem_service_pb2 import CreateProblemInput, ListProblemsInput, DescribeProblemInput, \
    UpdateProblemInput, ListVersionsInput
from eolymp.atlas.statement_pb2 import Statement
from eolymp.atlas.statement_service_pb2 import UpdateStatementInput, CreateStatementInput, DeleteStatementInput, \
    ListStatementsInput
from eolymp.atlas import ListSubmissionsInput
from eolymp.atlas.submission_service_http import SubmissionServiceClient
from eolymp.ecm.content_pb2 import Content
from eolymp.wellknown.expression_pb2 import ExpressionID, ExpressionEnum

from peolymp.abstract import AbstractAPI


class AtlasAPI(AbstractAPI):

    def __init__(self, space, problem_id=None):
        super(AtlasAPI, self).__init__(space)
        self.problem_id = None
        self.problem_client = ProblemServiceClient(self.http_client, url=self.get_url())
        self.problem_id = problem_id
        self.submission_client = SubmissionServiceClient(self.http_client, url=self.get_url())
        self.statement_client = StatementServiceClient(self.http_client, url=self.get_url())

    def get_url(self):
        url = super(AtlasAPI, self).get_url()
        if self.problem_id:
            url += "/problems/" + self.problem_id
        return url

    def get_submissions(self, problem_id):
        exp = ExpressionEnum(value="ACCEPTED")
        setattr(exp, 'is', 1)
        exp2 = ExpressionID(value=problem_id)
        setattr(exp2, 'is', 1)
        filters = ListSubmissionsInput.Filter(problem_id=[exp2], verdict=[exp])
        return self.submission_client.ListSubmissions(ListSubmissionsInput(filters=filters))

    def create_problem_from_another_space(self, problem_link):
        return self.problem_client.CreateProblem(CreateProblemInput(problem=Problem(origin=problem_link))).problem_id

    def make_problem_visible(self, prob_id, visible=True):
        return self.problem_client.UpdateProblem(UpdateProblemInput(problem_id=prob_id, problem=Problem(visible=visible), patch=[UpdateProblemInput.VISIBLE]))

    def create_statement(self, prob_id, locale, title, link, source=""):
        s = statement_pb2.Statement(problem_id=prob_id, locale=locale, title=title, content="", download_link=link,
                                    format=statement_pb2.Statement.Format.TEX, source=source)
        print(self.statement_client.CreateStatement(CreateStatementInput(problem_id=prob_id, statement=s)))

    def update_statement(self, problem_id, statement):
        print(self.statement_client.UpdateStatement(
            UpdateStatementInput(statement_id=statement.id, statement=statement)))

    def delete_statement(self, prob_id, statement_id):
        self.statement_client.DeleteStatement(DeleteStatementInput(statement_id=statement_id, problem_id=prob_id))

    def get_statements(self, prob_id, version=None):
        extra = [Statement.CONTENT_VALUE]
        input_data = ListStatementsInput(version=version, extra=extra) if version else ListStatementsInput(extra=extra)
        return self.statement_client.ListStatements(input_data).items

    def get_problems(self):
        def __get_problems(offset, size):
            return self.problem_client.ListProblems(request=ListProblemsInput(offset=offset, size=size))

        return self.get_many(__get_problems)

    def describe_problem(self, problem_id):
        return self.problem_client.DescribeProblem(DescribeProblemInput(problem_id=problem_id)).problem

    def update_origin(self, problem_id, origin):
        return self.problem_client.UpdateProblem(UpdateProblemInput(problem_id=problem_id, problem=Problem(origin=origin), patch=[UpdateProblemInput.ORIGIN]))

    def update_source(self, problem_id, statement_id, source):
        return self.statement_client.UpdateStatement(UpdateStatementInput(statement_id=statement_id, statement=Statement(source=source), patch=[Statement.PATCH_SOURCE]))

    def update_latex(self, problem_id, statement_id, latex=" "):
        return self.statement_client.UpdateStatement(UpdateStatementInput(statement_id=statement_id, statement=Statement(content=Content(latex=latex)), patch=[Statement.PATCH_CONTENT]))

    def get_versions(self, problem_id):
        def __get_versions(offset, size):
            return self.problem_client.ListVersions(request=ListVersionsInput(offset=offset, size=size, problem_id=problem_id))

        return self.get_many(__get_versions)
