import re
import base64

from odoo import models, fields, api
from odoo.tools import misc

from odoo.addons.base.models.assetsbundle import EXTENSIONS


class ColorEditor(models.AbstractModel):

    _name = 'fusion_backend_theme.color_editor'
    _description = 'Theme Color Editor'

    @api.model
    def _get_custom_url(self, url, bundle):
        return f'/_custom/{bundle}{url}'

    @api.model
    def _get_url_info(self, url):
        regex = re.compile(
            r'^(/_custom/([^/]+))?/(\w+)/([/\w.]+\.\w+)$'
        )
        match = regex.match(url)
        if not match:
            return False
        return {
            'module': match.group(3),
            'resource_path': match.group(4),
            'customized': bool(match.group(1)),
            'bundle': match.group(2) or False
        }

    @api.model
    def _find_attachment(self, custom_url):
        return self.env['ir.attachment'].search([
            ('url', '=', custom_url)
        ])

    @api.model
    def _find_asset(self, custom_url):
        return self.env['ir.asset'].search([
            ('path', 'like', custom_url)
        ])

    @api.model
    def _read_scss(self, url, bundle):
        custom_url = self._get_custom_url(url, bundle)
        url_info = self._get_url_info(custom_url)
        if url_info and url_info['customized']:
            attachment = self._find_attachment(custom_url)
            if attachment:
                return base64.b64decode(attachment.datas)
        with misc.file_open(
            url.strip('/'), 'rb', filter_ext=EXTENSIONS
        ) as f:
            return f.read()

    def _extract_variable(self, content, variable):
        value = re.search(
            fr'\$o_fusion_{variable}\:?\s(.*?);', content
        )
        return value and value.group(1)

    def _extract_variables(self, content, variables):
        return {
            var: self._extract_variable(content, var)
            for var in variables
        }

    def _update_variables(self, content, variables):
        for variable in variables:
            if not variable.get("value"):
                continue
            content = re.sub(
                fr'{variable["name"]}\:?\s(.*?);',
                f'{variable["name"]}: {variable["value"]};',
                content
            )
        return content

    @api.model
    def _write_scss(self, url, bundle, content):
        custom_url = self._get_custom_url(url, bundle)
        asset_url = url[1:] if url.startswith(('/', '\\')) else url
        datas = base64.b64encode((content or '\n').encode('utf-8'))
        custom_attachment = self._find_attachment(custom_url)
        if custom_attachment:
            custom_attachment.write({'datas': datas})
            self.env.registry.clear_cache('assets')
        else:
            attachment_values = {
                'name': url.split('/')[-1],
                'type': 'binary',
                'mimetype': 'text/scss',
                'datas': datas,
                'url': custom_url,
            }
            asset_values = {
                'path': custom_url,
                'target': url,
                'directive': 'replace',
            }
            target_asset = self._find_asset(asset_url)
            if target_asset:
                asset_values['name'] = '%s override' % target_asset.name
                asset_values['bundle'] = target_asset.bundle
                asset_values['sequence'] = target_asset.sequence
            else:
                asset_values['name'] = '%s: replace %s' % (
                    bundle, custom_url.split('/')[-1]
                )
                asset_values['bundle'] = (
                    self.env['ir.asset']._get_related_bundle(url, bundle)
                )
            self.env['ir.attachment'].create(attachment_values)
            self.env['ir.asset'].create(asset_values)

    def get_variable_values(self, url, bundle, variables):
        content = self._read_scss(url, bundle)
        return self._extract_variables(
            content.decode('utf-8'), variables
        )

    def set_variable_values(self, url, bundle, variables):
        original = self._read_scss(url, bundle).decode('utf-8')
        content = self._update_variables(original, variables)
        self._write_scss(url, bundle, content)

    def reset_asset(self, url, bundle):
        custom_url = self._get_custom_url(url, bundle)
        self._find_attachment(custom_url).unlink()
        self._find_asset(custom_url).unlink()
