# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.

import datetime
import dateutil.parser as dparser
from re import findall as re_findall

from odoo import fields, models
from odoo.tools import get_lang


class StockMove(models.Model):
    _inherit = "stock.move"

    use_expiration_date = fields.Boolean(
        string='Use Expiration Date', related='product_id.use_expiration_date')

    def _generate_serial_move_line_commands(self, field_data, location_dest_id=False, origin_move_line=None):
        """Override to add a default `expiration_date` into the move lines values."""
        move_lines_commands = super()._generate_serial_move_line_commands(field_data, location_dest_id, origin_move_line)
        if self.product_id.use_expiration_date:
            date = fields.Datetime.today() + datetime.timedelta(days=self.product_id.expiration_time)
            for move_line_command in move_lines_commands:
                move_line_vals = move_line_command[2]
                if 'expiration_date' not in move_line_vals:
                    move_line_vals['expiration_date'] = date
        return move_lines_commands

    def _convert_string_into_field_data(self, string, options):
        res = super()._convert_string_into_field_data(string, options)
        if not res:
            try:
                datetime = dparser.parse(string, **options)
                if self and not self.use_expiration_date:
                    # The datetime was correctly parsed but this move's product doesn't use expiration date.
                    return "ignore"
                return {'expiration_date': datetime}
            except ValueError:
                pass
        return res

    def _get_formating_options(self, strings):
        options = super()._get_formating_options(strings)
        separators = "-/ "
        date_regex = f'[^{separators}]+'
        for string in strings:
            # Searches for a date.
            date_data = re_findall(date_regex, string)
            if len(date_data) < 2:  # Not enough data.
                continue
            value_1, value_2 = date_data[:2]
            if re_findall('[a-zA-Z]', value_1):
                # Assumes the first value is the mounth (written in letters). Don't add any option
                # as mounth as the first date's value is the default behavior for `dateutil.parse`.
                break
            # Try to guess if the first data is the day or the year.
            if int(value_1) > 31:
                options['yearfirst'] = True
                break
            elif int(value_1) > 12 and (re_findall('[a-zA-Z]', value_2) or int(value_2) <= 12):
                options['dayfirst'] = True
                break
            else:  # Too ambiguous, gets the option from the user's lang's date setting.
                user_lang_format = get_lang(self.env).date_format
                if re_findall('^%[mbB]', user_lang_format):  # First parameter is for month.
                    return options
                elif re_findall('^%[djaA]', user_lang_format):  # First parameter is for day.
                    options['dayfirst'] = True
                    break
                elif re_findall('^%[yY]', user_lang_format):  # First parameter is for year.
                    options['yearfirst'] = True
                    break
        return options

    def _update_reserved_quantity(self, need, location_id, lot_id=None, package_id=None, owner_id=None, strict=True):
        if self.product_id.use_expiration_date:
            return super(StockMove, self.with_context(with_expiration=self.date))._update_reserved_quantity(need, location_id, lot_id, package_id, owner_id, strict)
        return super()._update_reserved_quantity(need, location_id, lot_id, package_id, owner_id, strict)

    def _get_available_quantity(self, location_id, lot_id=None, package_id=None, owner_id=None, strict=False, allow_negative=False):
        if self.product_id.use_expiration_date:
            return super(StockMove, self.with_context(with_expiration=self.date))._get_available_quantity(location_id, lot_id, package_id, owner_id, strict, allow_negative)
        return super()._get_available_quantity(location_id, lot_id, package_id, owner_id, strict, allow_negative)
