import logging
import pathlib
from functools import cached_property

import yaml
from core.utils.db import fast_first
from rest_framework import serializers

from .models import ProductTourInteractionData, ProductTourState, UserProductTour

logger = logging.getLogger(__name__)

PRODUCT_TOURS_CONFIGS_DIR = pathlib.Path(__file__).parent / 'configs'


class UserProductTourSerializer(serializers.ModelSerializer):
    # steps is a list of steps in the tour loaded from the yaml file
    steps = serializers.SerializerMethodField(read_only=True)
    # awaiting is a boolean that indicates if the tour is awaiting other tours in the list of "dependencies"
    awaiting = serializers.SerializerMethodField(read_only=True)

    class Meta:
        model = UserProductTour
        fields = '__all__'

    @cached_property
    def available_tours(self):
        return {pathlib.Path(f).stem for f in PRODUCT_TOURS_CONFIGS_DIR.iterdir()}

    def validate_name(self, value):

        if value not in self.available_tours:
            raise serializers.ValidationError(
                f'Product tour {value} not found. Available tours: {self.available_tours}'
            )

        return value

    @cached_property
    def load_tour_config(self):
        # TODO: get product tour from yaml file. Later we move it to remote storage, e.g. S3
        filepath = PRODUCT_TOURS_CONFIGS_DIR / f'{self.context["name"]}.yml'
        with open(filepath, 'r') as f:
            return yaml.safe_load(f)

    def get_awaiting(self, obj):
        config = self.load_tour_config
        dependencies = config.get('dependencies', [])
        for dependency in dependencies:
            tour = fast_first(UserProductTour.objects.filter(user=self.context['request'].user, name=dependency))
            if not tour or tour.state != ProductTourState.COMPLETED:
                logger.info(f'Tour {dependency} is not completed: skipping tour {self.context["name"]}')
                return True
        return False

    def get_steps(self, obj):
        config = self.load_tour_config
        return config.get('steps', [])

    def validate_interaction_data(self, value):
        try:
            # Validate interaction data using pydantic model
            ProductTourInteractionData(**value)
            return value
        except Exception:
            raise serializers.ValidationError('Invalid product tour interaction data format.')
