import os
import sys
from pathlib import Path

from click.testing import CliRunner
from xsdata.cli import cli
from xsdata.models.config import GeneratorConfig
from xsdata.utils.testing import ClassFactory, FactoryTestCase

from xsdata_odoo.generator import OdooGenerator


class OdooGeneratorTests(FactoryTestCase):
    def setUp(self):
        super().setUp()
        config = GeneratorConfig()
        self.generator = OdooGenerator(config)

    def test_render(self):
        if os.environ.get("XSDATA_SCHEMA"):
            del os.environ["XSDATA_SCHEMA"]
        if os.environ.get("XSDATA_VERSION"):
            del os.environ["XSDATA_VERSION"]

        classes = [
            ClassFactory.elements(2, package="generated"),
            ClassFactory.elements(3, package="generated"),
        ]

        iterator = self.generator.render(classes)

        actual = [(out.path, out.title, out.source) for out in iterator]
        self.assertEqual(1, len(actual))
        self.assertEqual(3, len(actual[0]))
        self.assertIsInstance(actual[0][0], Path)
        self.assertTrue(actual[0][0].is_absolute())
        self.assertEqual("generated.tests", actual[0][1])
        self.assertEqual(
            str(Path("generated/tests.py")),
            str(actual[0][0].relative_to(Path.cwd())),
        )

        # this is the expected with Ruff formatting:
        expected = """# Copyright 2025 Akretion - Raphaël Valyi <raphael.valyi@akretion.com>
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0.en.html).
# Generated by https://github.com/akretion/xsdata-odoo

import textwrap
from odoo import fields, models

__NAMESPACE__ = "xsdata"


class ClassB(models.AbstractModel):
    _description = "class_B"
    _name = "spec.10.classb"
    _inherit = "spec.mixin.spec"
    _binding_type = "ClassB"



    spec10_attr_B = fields.Char(
        string="attr_B"
    )

    spec10_attr_C = fields.Char(
        string="attr_C"
    )


class ClassC(models.AbstractModel):
    _description = "class_C"
    _name = "spec.10.classc"
    _inherit = "spec.mixin.spec"
    _binding_type = "ClassC"



    spec10_attr_D = fields.Char(
        string="attr_D"
    )

    spec10_attr_E = fields.Char(
        string="attr_E"
    )

    spec10_attr_F = fields.Char(
        string="attr_F"
    )
"""
        # for convenience we remove trailing spaces:
        expected_lines = [line.rstrip() for line in expected.splitlines()]
        expected_clean = "\n".join(expected_lines)
        actual_lines = [line.rstrip() for line in actual[0][2].splitlines()]
        actual_clean = "\n".join(actual_lines)
        self.assertEqual(expected_clean, actual_clean)

    def test_complete_po(self):
        os.environ["XSDATA_SCHEMA"] = "poxsd"
        if os.environ.get("XSDATA_VERSION"):
            del os.environ["XSDATA_VERSION"]

        runner = CliRunner()
        schema = Path(__file__).parent.joinpath("fixtures/po/po.xsd")
        os.chdir(Path(__file__).parent.parent)

        result = runner.invoke(
            cli,
            [
                str(schema),
                "--package",
                "generated.po.models",
                "--structure-style=single-package",
                "--output",
                "odoo",
            ],
            catch_exceptions=True,
        )

        self.assertIsNone(result.exception)

        if "win" not in sys.platform.lower():
            expected = "to be read 1"
            generated = "to be read 2"
            with open("tests/fixtures/po/models.py") as f:
                expected = f.read()
            with open("generated/po/models.py") as f:
                generated = f.read()
            self.assertEqual(expected, generated)

    def test_complete_po_with_nesting(self):
        if os.environ.get("XSDATA_SCHEMA"):
            del os.environ["XSDATA_SCHEMA"]
        if os.environ.get("XSDATA_VERSION"):
            del os.environ["XSDATA_VERSION"]

        runner = CliRunner()
        schema = Path(__file__).parent.joinpath("fixtures/po_with_nesting/po.xsd")
        os.chdir(Path(__file__).parent.parent)

        result = runner.invoke(
            cli,
            [
                str(schema),
                "--package",
                "generated.po_with_nesting.models",
                "--structure-style=single-package",
                "--output",
                "odoo",
            ],
            catch_exceptions=True,
        )

        self.assertIsNone(result.exception)

        if "win" not in sys.platform.lower():
            expected = "to be read 1"
            generated = "to be read 2"
            with open("tests/fixtures/po_with_nesting/models.py") as f:
                expected = f.read()
            with open("generated/po_with_nesting/models.py") as f:
                generated = f.read()
            self.assertEqual(expected, generated)

    def test_complete_nfe(self):
        os.environ["XSDATA_SCHEMA"] = "nfe"
        os.environ["XSDATA_VERSION"] = "40"
        os.environ["XSDATA_SKIP"] = r"^ICMS.ICMS\d+|^ICMS.ICMSSN\d+"
        os.environ["XSDATA_LANG"] = "portuguese"

        runner = CliRunner()
        schema = Path(__file__).parent.joinpath("fixtures/nfe/leiauteNFe_v4.00.xsd")
        os.chdir(Path(__file__).parent.parent)

        result = runner.invoke(
            cli,
            [
                str(schema),
                "--package",
                "generated.nfe.v4_0.models",
                "--structure-style=single-package",
                "--output",
                "odoo",
            ],
            catch_exceptions=True,
        )

        self.assertIsNone(result.exception)

        if sys.version_info[:2] > (3, 9) and "win" not in sys.platform.lower():
            expected = "to be read 1"
            generated = "to be read 2"
            with open("tests/fixtures/nfe/models.py") as f:
                expected = f.read()
            with open("generated/nfe/v4_0/models.py") as f:
                generated = f.read()
            self.assertEqual(expected, generated)
