"""a class based approach for interacting with Domo Datasets"""

# AUTOGENERATED! DO NOT EDIT! File to edit: ../../nbs/classes/50_DomoDataset_Schema.ipynb.

# %% auto 0
__all__ = ['DatasetSchema_Types', 'DomoDataset_Schema_Column', 'DomoDataset_Schema', 'DatasetSchema_InvalidSchema']

# %% ../../nbs/classes/50_DomoDataset_Schema.ipynb 3
from dataclasses import dataclass, field
from typing import List, Any
from enum import Enum

from nbdev.showdoc import patch_to

import domolibrary.utils.DictDot as util_dd

import domolibrary.client.DomoAuth as dmda
import domolibrary.client.DomoError as dmde
import pandas as pd

import domolibrary.routes.dataset as dataset_routes

# %% ../../nbs/classes/50_DomoDataset_Schema.ipynb 7
class DatasetSchema_Types(Enum):
    STRING = "STRING"
    DOUBLE = "DOUBLE"
    LONG = "LONG"
    DATE = "DATE"
    DATETIME = "DATETIME"


@dataclass
class DomoDataset_Schema_Column:
    name: str
    id: str
    type: DatasetSchema_Types
    order: int = 0
    visible: bool = True
    upsert_key: bool = False

    def __eq__(self, other):
        return self.id == other.id

    @classmethod
    def _from_json(cls, json_obj):
        dd = util_dd.DictDot(json_obj)
        return cls(
            name=dd.name,
            id=dd.id,
            type=dd.type,
            visible=dd.visible or dd.isVisible or True,
            upsert_key=dd.upsertKey or False,
            order=dd.order or 0,
        )

    def to_dict(self):
        s = self.__dict__
        s["upsertKey"] = s.pop("upsert_key") if "upsert_key" in s else False
        return s




# %% ../../nbs/classes/50_DomoDataset_Schema.ipynb 9
@dataclass
class DomoDataset_Schema:
    """class for interacting with dataset schemas"""

    auth : dmda.DomoAuth = field(repr = False)
    dataset_id : str 

    parent: Any = field(repr = False, default = None)
    columns: List[DomoDataset_Schema_Column] = field(default_factory=list)

    def __post_init__(self):
        if self.parent: 
            self.auth = self.parent.auth
            self.dataset_id = self.parent.id


    @classmethod
    def _from_parent(cls, parent):
        ds = cls(
            parent = parent,
            auth = parent.auth,
            dataset_id = parent.id
        )

        parent.Schema = ds
        return ds

    async def get(
        self,
        debug_api: bool = False,
        return_raw: bool = False,  # return the raw response
    ) -> List[DomoDataset_Schema_Column]:
        """method that retrieves schema for a dataset"""


        res = await dataset_routes.get_schema(
            auth=self.auth, dataset_id=self.dataset_id, debug_api=debug_api
        )

        if return_raw:
            return res.response

        self.columns = [
            DomoDataset_Schema_Column._from_json(json_obj=obj)
            for obj in res.response.get("tables")[0].get("columns")
        ]

        return self.columns

# %% ../../nbs/classes/50_DomoDataset_Schema.ipynb 11
class DatasetSchema_InvalidSchema(dmde.DomoError):
    def __init__(self, domo_instance, dataset_id, missing_columns, dataset_name=None, message = None):

        if dataset_id:
            message = f"{dataset_id}{f' - {dataset_name}' if dataset_name else ''} is missing columns {', '.join(missing_columns)}"

        super().__init__(domo_instance=domo_instance, message=message)


@patch_to(DomoDataset_Schema)
async def _test_missing_columns(
    self: DomoDataset_Schema,
    df: pd.DataFrame,
    dataset_id=None,
    auth: dmda.DomoAuth = None,
):

    dataset_id = dataset_id or self.parent.id
    auth = auth or self.parent.auth

    await self.get()

    missing_columns = [
        col for col in df.columns if col not in [scol.name for scol in self.columns]
    ]

    if len(missing_columns) > 0:
        raise DatasetSchema_InvalidSchema(
            domo_instance=auth.domo_instance,
            dataset_id=dataset_id,
            missing_columns=missing_columns,
        )

    return False

# %% ../../nbs/classes/50_DomoDataset_Schema.ipynb 14
@patch_to(DomoDataset_Schema)
async def reset_col_order(self: DomoDataset_Schema, df: pd.DataFrame):

    await self.get()

    if len(self.columns) != len(df.columns):
        raise Exception("")

    for index, col in enumerate(self.schema.columns):
        col.order = col.order if col.order > 0 else index

    # for index, schema in enumerate(consol_ds.schema.columns):
    #     schema.order = index

    # schema = {'columns': [col.__dict__ for col in consol_ds.schema.columns]}
    # schema

    # import domolibrary.routes.dataset as dataset_routes
    # await dataset_routes.alter_schema(auth = consol_auth, dataset_id = consol_ds.id, schema_obj = schema)

# %% ../../nbs/classes/50_DomoDataset_Schema.ipynb 15
@patch_to(DomoDataset_Schema)
def to_dict(self: DomoDataset_Schema):
    return {"columns": [col.to_dict() for col in self.columns]}

# %% ../../nbs/classes/50_DomoDataset_Schema.ipynb 17
@patch_to(DomoDataset_Schema)
def add_col(
    self: DomoDataset_Schema, col: DomoDataset_Schema_Column, debug_prn: bool = False
):

    if col in self.columns and debug_prn:
        print(
            f"column - {col.name} already in dataset {self.parent.name if self.parent else '' }"
        )

    if col not in self.columns:
        self.columns.append(col)

    return self.columns


@patch_to(DomoDataset_Schema)
def remove_col(
    self: DomoDataset_Schema,
    col_to_remove: DomoDataset_Schema_Column,
    debug_prn: bool = False,
):

    [
        self.columns.pop(index)
        for index, col in enumerate(self.columns)
        if col == col_to_remove
    ]

    return self.columns

# %% ../../nbs/classes/50_DomoDataset_Schema.ipynb 19
class CRUD_Dataset_Error(dmde.DomoError):
    def __init__(self, auth, res, message):
        super().__init__(
            status = res.status,
            function_name= res.traceback_details.function_name,
            parent_class = res.traceback_details.parent_class,
            message = message or res.response,
            domo_instance = auth.domo_instance
        )

@patch_to(DomoDataset_Schema)
async def alter_schema(
    self: DomoDataset_Schema,
    dataset_id: str = None,
    auth: dmda.DomoAuth = None,
    return_raw: bool = False,
    debug_api: bool = False,
):

    dataset_id = dataset_id or self.parent.id
    auth = auth or self.parent.auth

    schema_obj = self.to_dict()

    if return_raw:
        return schema_obj

    res =  await dataset_routes.alter_schema(
        dataset_id=dataset_id, auth=auth, schema_obj=schema_obj, debug_api=debug_api
    )

    if not res.is_success:
        raise CRUD_Dataset_Error(auth = auth , res = res, message = f"unable to alter schema for {dataset_id}")

    return res
