from unittest import TestCase
from unittest.mock import MagicMock, patch
import uuid
import factory
import pandas as pd
import io

from objects.policy import Policy
from utils import constants
from tests.fixtures.routine_fixtures import RoutineFactory, RoutineDictFactory
from faker import Faker
fake = Faker()
# Patch pandas.read_csv before anything imports Routine
fake_df = pd.DataFrame({'value': ['World', 'Bar']}, index=['Hello', 'Foo'])

with patch('pandas.read_csv', return_value=fake_df):
    from objects.policy_level import PolicyLevel
    from objects.routine import Routine
    from utils import var_names

def routine_from_dict(data):
    """Convert a routine dict to a Routine object."""
    return Routine(
        routine_id=data.get("routine_id"),
        organization_id=data.get("organization_id"),
        routine_name=data.get("routine_name"),
        routine_timezone=data.get("routine_timezone"),
        routine_layers=data.get("routine_layers"),
        reference_id=data.get("reference_id"),
        associated_policies=data.get("associated_policies"),
    )

def policy_level_from_dict(data):
    """Convert a PolicyLevel dict to a PolicyLevel object, converting routines as well."""
    return PolicyLevel(
        # level=data.get("level"),

        level= data.get("level", 1),  # Default to level 1 if not provided
        minutes=data.get("minutes"),
        # minutes=data["minutes"],
        routines=[routine_from_dict(r) for r in data.get("routines", [])]
    )
fake = Faker()

class PolicyLevelDictFactory(factory.Factory):
    class Meta:
        model = dict

    as_json = False

    # Required by create_level()
    assignee_level = factory.Sequence(lambda n: n)
    level_minutes = factory.Faker("random_int", min=1, max=60)

    @factory.lazy_attribute
    def routines(self):
        # Use RoutineDictFactory for dicts, pass as_json
        return [RoutineDictFactory(as_json=self.as_json) for _ in range(2)]

    
class PolicyLevelFactory(factory.Factory):
    class Meta:
        model = PolicyLevel

    level = factory.Sequence(lambda n: n)
    minutes = factory.Faker("random_int", min=1, max=60)
    as_dict = True
    as_json = False

    @factory.lazy_attribute
    def routines(self):
        as_dict = getattr(self, "as_dict", False)
        as_json = getattr(self, "as_json", False)
        if as_dict:
            # Use RoutineDictFactory for dicts, pass as_json
            return [RoutineDictFactory(as_json=as_json) for _ in range(3)]
        else:
            # Use RoutineFactory for objects, do NOT pass as_json
            return [RoutineFactory() for _ in range(3)]

    @classmethod
    def _create(cls, model_class, *args, **kwargs):
        as_dict = kwargs.pop("as_dict", False)
        as_json = kwargs.pop("as_json", False)
        obj = model_class(*args, **kwargs)
        obj.as_dict = as_dict
        obj.as_json = as_json
        return obj

    @classmethod
    def _build(cls, model_class, *args, **kwargs):
        kwargs.pop("as_dict", None)
        kwargs.pop("as_json", None)
        return model_class(*args, **kwargs)



class PolicyFactory(factory.Factory):
    policy_id = factory.Sequence(lambda n: f"policy_{n}")
    policy_name = factory.Sequence(lambda n: f"Policy {n}")
    policy_type = constants.user_policy
    reference_id = factory.LazyFunction(uuid.uuid4)
    organization_id = "org_1"
    associated_services = factory.LazyFunction(
        lambda: [["service1", "serv-ref-1"], ["service2", "serv-ref-2"]]
    )
    tags = factory.LazyFunction(lambda: ["tag1", "tag2"])
    levels = factory.LazyFunction(lambda: [PolicyLevelFactory() for _ in range(3)])