import random
from django.db import models
from django.utils.timezone import now, localtime
import datetime
from utils import const
import utils


class Ingredient(models.Model):
    name = models.CharField(max_length=128)
    unit = models.CharField(max_length=32)
    status = models.CharField(max_length=32, default=const.INGREDIENT_STATUS_ACTIVE)


class RecipeIngredient(models.Model):
    recipe = models.ForeignKey('Recipe', on_delete=models.CASCADE, related_name='recipe_ingredients')
    ingredient = models.ForeignKey(Ingredient, on_delete=models.CASCADE, related_name='recipe_ingredients')
    status = models.CharField(max_length=32, default=const.INGREDIENT_STATUS_ACTIVE)
    quantity = models.FloatField()

    def serialize(self):
        return {
            'id': self.id,
            'recipe': {'id': self.recipe.id, 'name': self.recipe.name},
            'ingredient': {'id': self.ingredient.id, 'name': self.ingredient.name, 'unit': self.ingredient.unit},
            'quantity': self.quantity,
        }


class Recipe(models.Model):
    name = models.CharField(max_length=128)
    recipe_type = models.CharField(max_length=32, default=const.RECIPE_TYPE_MEAT)
    status = models.CharField(max_length=32, default=const.RECIPE_STATUS_ACTIVE)
    note = models.TextField(null=True)
    rate = models.IntegerField(default=0)
    difficulty = models.IntegerField(default=0)

    def serialize(self, verbose=False):
        data = {'id': self.id, 'name': self.name, 'recipe_type': self.recipe_type}
        if verbose:
            data.update(
                {
                    'difficulty': self.difficulty,
                    'rate': self.rate,
                    'note': self.note,
                    'recipe_ingredients': self.get_ingredients(),
                }
            )

        return data

    def get_ingredients(self):
        return [i.serialize() for i in self.recipeingredient_set.order_by('id')]

    @classmethod
    def create_from_str(cls, content):
        content = content.strip()
        if not content:
            return
        name, *data = content.split(' ')
        recipe_type = rate = difficulty = None
        keys = [recipe_type, rate, difficulty]
        for x in range(len(data)):
            keys[x] = data[x]
        recipe_type, rate, difficulty = keys

        if recipe_type == '肉':
            recipe_type = const.RECIPE_TYPE_MEAT
        elif recipe_type == '菜':
            recipe_type = const.RECIPE_TYPE_VEGETABLE
        elif recipe_type == '汤':
            recipe_type = const.RECIPE_TYPE_SOUP
        else:
            recipe_type = const.RECIPE_TYPE_MEAT
        if rate:
            try:
                rate = int(rate)
            except:
                rate = 0
        else:
            rate = 0
        if difficulty:
            try:
                difficulty = int(difficulty)
            except:
                difficulty = 0
        else:
            difficulty = 0
        recipe = cls.objects.create(
            name=name, recipe_type=recipe_type, rate=rate, difficulty=difficulty, status=const.RECIPE_STATUS_ACTIVE
        )
        return recipe

    @property
    def display_recipe_type(self):
        if self.recipe_type == const.RECIPE_TYPE_VEGETABLE:
            return '菜'
        elif self.recipe_type == const.RECIPE_TYPE_MEAT:
            return '肉'
        elif self.recipe_type == const.RECIPE_TYPE_SOUP:
            return '汤'
        return '肉'

    @property
    def display_rate(self):
        return '🍚' * self.rate

    @property
    def display_difficult(self):
        return '⭐️' * self.difficulty

    def construct_lart_card(self):

        data = {
            "config": {"wide_screen_mode": True},
            "header": {"title": {"tag": "plain_text", "content": self.name}, "template": "blue"},
            "elements": [
                {
                    "tag": "markdown",
                    "content": "**类型**：%s\n**评分**：%s\n**难度**：%s"
                    % (self.display_recipe_type, self.display_rate, self.display_difficult),
                },
                {
                    "tag": "action",
                    "actions": [
                        {
                            "tag": "button",
                            "text": {"tag": "plain_text", "content": "查看"},
                            "multi_url": {
                                "url": "https://recipe.tunpok.com/recipe/%s" % self.id,
                                "android_url": "https://recipe.tunpok.com/recipe-mobile/recipe/%s" % self.id,
                                "ios_url": "https://recipe.tunpok.com/recipe-mobile/recipe/%s" % self.id,
                                "pc_url": "https://recipe.tunpok.com/recipe/%s" % self.id,
                            },
                            "type": "primary",
                        },
                        {"tag": "button", "text": {"tag": "plain_text", "content": "删除"}, "type": "danger"},
                    ],
                },
            ],
        }
        return data


class DailyRecipe(models.Model):
    recipes = models.ManyToManyField(Recipe)
    date = models.DateField()
    meal_type = models.CharField(max_length=32, default=const.DAILY_RECIPE_MEAL_TYPE_SUPPER)

    def generate_recipe(self, prev_recipes=None, ignore_prev=False):
        if not prev_recipes:
            prev_recipes = []
        if ignore_prev:
            prev_recipes = []

        recipes = []
        retry = 5

        # meat
        for x in range(0, 2):
            while True:
                recipe = (
                    Recipe.objects.filter(recipe_type=const.RECIPE_TYPE_MEAT)
                    .exclude(status=const.RECIPE_STATUS_DELETED)
                    .order_by('?')
                    .first()
                )
                if recipe and recipe.id not in recipes and recipe.id not in prev_recipes:
                    recipes.append(recipe.id)
                    break
                else:
                    retry -= 1
                if retry <= 0:
                    retry = 5
                    break

        # vegetable
        for x in range(0, 1):
            while True:
                recipe = (
                    Recipe.objects.filter(recipe_type=const.RECIPE_TYPE_VEGETABLE)
                    .exclude(status=const.RECIPE_STATUS_DELETED)
                    .order_by('?')
                    .first()
                )
                if recipe and recipe.id not in recipes and recipe.id not in prev_recipes:
                    recipes.append(recipe.id)
                    break
                else:
                    retry -= 1
                if retry <= 0:
                    retry = 5
                    break

        # soup
        if random.randint(0, 2):
            recipe = (
                Recipe.objects.filter(recipe_type=const.RECIPE_TYPE_SOUP)
                .exclude(status=const.RECIPE_STATUS_DELETED)
                .order_by('?')
                .first()
            )
            # if recipe not in recipes and recipe not in prev_recipes:
            if recipe:
                recipes.append(recipe.id)

        self.recipes.set(Recipe.objects.filter(id__in=recipes))

    def serialize(self):
        data = {const.RECIPE_TYPE_MEAT: [], const.RECIPE_TYPE_VEGETABLE: [], const.RECIPE_TYPE_SOUP: []}
        for key_, value_ in data.items():
            for recipe in self.recipes.filter(recipe_type=key_).order_by('id'):
                value_.append(recipe.serialize())

        date = now()
        date = date.replace(year=self.date.year, month=self.date.month, day=self.date.day, hour=0, minute=0)
        data['date'] = utils.timestamp_of(utils.day_start(date))
        data['id'] = self.id
        return data

    @classmethod
    def get_week_recipe_data(cls):
        today = localtime()
        week_start = (today - datetime.timedelta(days=today.weekday())).date()
        week_end = week_start + datetime.timedelta(days=6)
        daily_recipes = cls.objects.filter(date__gte=week_start, date__lte=week_end).order_by('date')
        data = [{}] * (7 - len(daily_recipes))

        for daily_recipe in daily_recipes:
            data.append(daily_recipe.serialize())
        return data
