from sqlite3 import Connection
from typing import (
    Dict,
    List,
    Optional,
    Union,
)

from dbapitemplate import DbApiTemplate
from nreports.model import ProductData
from nreports.repository import ProductRepository


class SqliteProductRepository(ProductRepository):

    def __init__(
        self,
        conn: Connection,
    ) -> None:

        self._conn = DbApiTemplate(conn=conn)
        self._product_data = self._load_products_data()

    def _load_products_data(
        self,
    ) -> Dict[int, ProductData]:

        cfh_products = self._get_cfh_products()
        products_data: Dict[int, ProductData] = {}

        def mapper(
            row,
        ) -> None:

            product_code = int(row["ProductCode"])
            product_name = row["ProductName"]
            product_type = row["ProductType"].replace("TYPE_", "")

            products_data[product_code] = ProductData(
                product_name=product_name,
                product_type=product_type,
                product_cfh=product_code in cfh_products,
            )

        self._conn.execute(
            sql=self._get_product_name_and_type_query,
            mapper=mapper,
        )
        return products_data

    def _get_cfh_products(
        self,
    ) -> List[int]:

        cfh_products: List[int] = []

        def mapper(
            row,
        ) -> None:

            cfh_products.append(int(row["ProductCode"]))

        self._conn.execute(
            sql=self._get_cfh_products_query,
            mapper=mapper,
        )
        return cfh_products

    def get_product_data(
        self,
        product_id: Union[int, str],
    ) -> Optional[ProductData]:

        return self._product_data.get(product_id)

    _get_product_name_and_type_query = """
        SELECT DISTINCT
            p.ProductCode,
            p.ProductName,
            pt.TypeDescr AS ProductType
        FROM
            Product p
        INNER JOIN
            ProductKernelParams pkp
                ON pkp.ProductCode = p.ProductCode
        JOIN
            ProductType pt
                ON pt.TypeId = pkp.ProductType
      """

    _get_cfh_products_query = """
        SELECT
            ProductCode
        FROM
            ProductTags
        WHERE
            LOWER(Tag) = 'cfh=true'
        UNION
        SELECT
            ProductCode
        FROM
            ProductCustomParams
        WHERE
            LOWER(CustomParamId) = 'cfh'
            AND LOWER(CustomParamValue) = 'true'
    """
