import datetime
import logging

from sqlalchemy.orm import selectinload

from src.config.logger import shop_logger
from src.data.repositories.base import BaseRepository
from sqlalchemy import select, delete
from src.data.model.schemas import agent as schema, CreateAgent
from typing import Sequence, List
from src.data.model.db import partner_agent as db
from src.data.model.db import base_db


class AgentRepository(BaseRepository):

    async def get_agents_partner(self, agent_id: int) -> Sequence[schema.AgentPartner]:
        """
        Loads partner of selected agent given by id
        :param agent_id: the id of selected agent
        :return: a sequence of partner of selected agent
        """
        stmt = select(db.AgentPartner).where(db.AgentPartner.agent_num == agent_id)
        query = await self.async_session.execute(stmt)
        partner_id_of_agent = query.scalars().all()

        result = []
        for partner in partner_id_of_agent:
            partner = await self.async_session.get(db.Partner, partner.partner_num)
            result += [
                schema.AgentPartner(
                    partner_id=partner.partner_num,
                    partner_name=partner.name
                )
            ]

        return result

    async def get_sales_order_types(self, partner_id: int) -> Sequence[schema.PartnerSalesOrderTypes]:
        """
        Loads sales order types of selected partner given by id
        :param partner_id: the id of selected partner
        :return: a sequence of sales order types for selected partner
        """
        stmt = (select(db.SalesOrderType).
                join(db.SalesOrderTypePartner).
                where(db.SalesOrderTypePartner.partner_num == partner_id))
        query = await self.async_session.scalars(stmt)
        return [
            schema.PartnerSalesOrderTypes(
                sales_order_type_code=sales_order_type.code,
                sales_order_type_designation=sales_order_type.designation
            )
            for sales_order_type in query.all() if sales_order_type.code != "201"
        ]

    async def create_agent(self, agent: CreateAgent):
        """
        Creates a new agent
        :param agent: agent data for creation
        :return:
        """
        agent_to_insert = db.Agent(
            agent_num=agent.number,
            name=agent.name,
            email=agent.email,
        )
        self.async_session.add(agent_to_insert)
        await self.async_session.commit()
        shop_logger.info(f"Agent created:{str(agent_to_insert)}")
        return {
            "success": True
        }

    async def get_partner(self, partner_id: int) -> schema.Partner:
        """
        Loads partner by id
        :param partner_id: the partner id
        :return: partner information
        """
        partner = await self.async_session.get(db.Partner, partner_id, options=[
            selectinload(db.Partner.shipping),
            selectinload(db.Partner.payment)
        ])

        return schema.Partner(
            name=partner.name,
            street=partner.street,
            postalcode=partner.postalcode,
            city=partner.city,
            land=partner.land,
            iso_code=partner.iso_code,
            surcharge_code=partner.surcharge_code,
            shipping=f"{partner.shipping.code}-{partner.shipping.designation}",
            payment=f"{partner.payment.code}-{partner.payment.designation}",
            allow_order=partner.allow_orders,
            searchstring="",
            email=partner.email
        )

    async def get_partner_email(self, user_id) -> str:
        user = await self.async_session.get(db.Partner, user_id)
        return user.email

    async def get_agent(self, username) -> schema.Agent:
        agent = await self.async_session.scalar(
            select(db.Agent).where(db.Agent.username == username)
        )
        return schema.Agent(
            name=agent.name,
            street=agent.street,
            postalcode=agent.postalcode,
            city=agent.city,
            land=agent.land,
            allow_order=True,
            searchstring="",
            agent_nr=agent.agent_num
        )

    async def change_partner_email(self, partner_id, email):
        partner = await self.async_session.get(db.Partner, partner_id)
        partner.email = email
        await self.async_session.merge(partner)
        await self.async_session.commit()