# -*- coding: utf-8 -*-
"""
Tests for gs123.datamatrix module.
"""
import os
import tempfile
import unittest

from gs123.datamatrix import GS1DataMatrix


class TestGS1DataMatrix(unittest.TestCase):
    """Tests for GS1DataMatrix generation."""

    ELEMENT_STRING = "(01)20614141073461(21)0000010020(17)261231(10)LOTA1"
    URN_SGTIN = "urn:epc:id:sgtin:0614141.207346.10020"
    URN_SSCC = "urn:epc:id:sscc:0614141.1234567890"

    # ------------------------------------------------------------------
    # Constructor tests
    # ------------------------------------------------------------------

    def test_basic_creation(self):
        dm = GS1DataMatrix(self.ELEMENT_STRING)
        self.assertIsNotNone(dm)
        self.assertEqual(dm.data, self.ELEMENT_STRING)

    def test_empty_raises(self):
        with self.assertRaises(ValueError):
            GS1DataMatrix("")

    def test_none_raises(self):
        with self.assertRaises(ValueError):
            GS1DataMatrix(None)

    # ------------------------------------------------------------------
    # from_urn tests
    # ------------------------------------------------------------------

    def test_from_urn_sgtin(self):
        dm = GS1DataMatrix.from_urn(
            self.URN_SGTIN,
            company_prefix_length=7,
            lot="LOTA1",
            expiration="261231",
        )
        self.assertIn("(01)", dm.data)
        self.assertIn("(21)", dm.data)
        self.assertIn("(17)", dm.data)
        self.assertIn("(10)", dm.data)
        self.assertIn("LOTA1", dm.data)

    def test_from_urn_sgtin_no_lot_expiry(self):
        dm = GS1DataMatrix.from_urn(
            self.URN_SGTIN,
            company_prefix_length=7,
        )
        self.assertIn("(01)", dm.data)
        self.assertIn("(21)", dm.data)
        self.assertNotIn("(17)", dm.data)
        self.assertNotIn("(10)", dm.data)

    def test_from_urn_sscc(self):
        dm = GS1DataMatrix.from_urn(
            self.URN_SSCC,
            company_prefix_length=7,
        )
        self.assertIn("(00)", dm.data)

    # ------------------------------------------------------------------
    # from_barcode tests
    # ------------------------------------------------------------------

    def test_from_barcode(self):
        dm = GS1DataMatrix.from_barcode(
            self.ELEMENT_STRING,
            company_prefix_length=7,
        )
        self.assertIn("(01)", dm.data)
        self.assertIn("LOTA1", dm.data)

    def test_from_barcode_override_lot(self):
        dm = GS1DataMatrix.from_barcode(
            self.ELEMENT_STRING,
            company_prefix_length=7,
            lot="NEWLOT",
        )
        self.assertIn("NEWLOT", dm.data)

    # ------------------------------------------------------------------
    # Matrix / size tests
    # ------------------------------------------------------------------

    def test_matrix_is_square(self):
        dm = GS1DataMatrix(self.ELEMENT_STRING)
        rows, cols = dm.symbol_size
        self.assertGreater(rows, 0)
        self.assertGreater(cols, 0)
        # Data Matrix is always even-dimensioned
        self.assertEqual(rows % 2, 0)
        self.assertEqual(cols % 2, 0)

    def test_matrix_values_binary(self):
        dm = GS1DataMatrix(self.ELEMENT_STRING)
        for row in dm.matrix:
            for val in row:
                self.assertIn(val, (0, 1))

    # ------------------------------------------------------------------
    # SVG output tests
    # ------------------------------------------------------------------

    def test_svg_returns_string(self):
        dm = GS1DataMatrix(self.ELEMENT_STRING)
        svg = dm.svg()
        self.assertIsInstance(svg, str)
        self.assertIn("<svg", svg)
        self.assertIn("</svg>", svg)

    def test_svg_scale(self):
        dm = GS1DataMatrix(self.ELEMENT_STRING)
        svg_small = dm.svg(scale=5)
        svg_large = dm.svg(scale=20)
        # Larger scale → larger SVG dimensions → more text
        self.assertGreater(len(svg_large), len(svg_small))

    def test_save_svg(self):
        dm = GS1DataMatrix(self.ELEMENT_STRING)
        with tempfile.NamedTemporaryFile(suffix=".svg", delete=False) as f:
            path = f.name
        try:
            dm.save_svg(path)
            with open(path) as f:
                content = f.read()
            self.assertIn("<svg", content)
        finally:
            os.unlink(path)

    # ------------------------------------------------------------------
    # PNG output tests
    # ------------------------------------------------------------------

    def test_png_returns_bytes(self):
        dm = GS1DataMatrix(self.ELEMENT_STRING)
        data = dm.png()
        self.assertIsInstance(data, bytes)
        # PNG magic bytes
        self.assertTrue(data.startswith(b"\x89PNG"))

    def test_png_scale(self):
        dm = GS1DataMatrix(self.ELEMENT_STRING)
        png_small = dm.png(scale=5)
        png_large = dm.png(scale=20)
        self.assertGreater(len(png_large), len(png_small))

    def test_save_png(self):
        dm = GS1DataMatrix(self.ELEMENT_STRING)
        with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as f:
            path = f.name
        try:
            dm.save_png(path, scale=8)
            with open(path, "rb") as f:
                data = f.read()
            self.assertTrue(data.startswith(b"\x89PNG"))
        finally:
            os.unlink(path)

    # ------------------------------------------------------------------
    # repr / str tests
    # ------------------------------------------------------------------

    def test_repr(self):
        dm = GS1DataMatrix(self.ELEMENT_STRING)
        r = repr(dm)
        self.assertIn("GS1DataMatrix", r)
        self.assertIn("24x24", r)  # expected size for this payload

    def test_str(self):
        dm = GS1DataMatrix(self.ELEMENT_STRING)
        self.assertEqual(str(dm), self.ELEMENT_STRING)

    # ------------------------------------------------------------------
    # Various GS1 element strings
    # ------------------------------------------------------------------

    def test_bare_01_21(self):
        """Bare GTIN + serial, no lot/expiry."""
        dm = GS1DataMatrix("(01)00361414000024(21)SN12345")
        self.assertGreater(dm.symbol_size[0], 0)

    def test_long_serial(self):
        """Serial number up to 20 chars (GS1 max)."""
        dm = GS1DataMatrix(
            "(01)00361414000024(21)ABCDEFGHIJKLMNOPQRST"
        )
        self.assertGreater(dm.symbol_size[0], 0)

    def test_sscc_barcode(self):
        dm = GS1DataMatrix("(00)006141411234567890")
        self.assertGreater(dm.symbol_size[0], 0)


if __name__ == "__main__":
    unittest.main()
