"""Convert iColorDisplay DeviceCorrections.txt to Argyll CCMX files.

It parses the input file, extracts relevant data, and generates CCMX files in
the specified format for use with color calibration tools.
"""

import json
import os
import sys
import time

CCMX_TEMPLATE = """CCMX

DESCRIPTOR "%(Name)s"
KEYWORD "INSTRUMENT"
INSTRUMENT "%(Device)s"
KEYWORD "DISPLAY"
DISPLAY "%(Display)s"
KEYWORD "DISPLAY_TYPE_BASE_ID"
DISPLAY_TYPE_BASE_ID "1"
KEYWORD "REFERENCE"
REFERENCE "%(ReferenceDevice)s"
ORIGINATOR "%(Originator)s"
CREATED "%(DateTime)s"
KEYWORD "COLOR_REP"
COLOR_REP "XYZ"

NUMBER_OF_FIELDS 3
BEGIN_DATA_FORMAT
XYZ_X XYZ_Y XYZ_Z
END_DATA_FORMAT

NUMBER_OF_SETS 3
BEGIN_DATA
%(MatrixXYZ)s
END_DATA
"""


def convert_devicecorrections_to_ccmx(path: str, target_dir: str) -> tuple[int, int]:
    """Convert iColorDisplay DeviceCorrections.txt to individual Argyll CCMX files.

    Args:
        path (str): Path to the DeviceCorrections.txt file.
        target_dir (str): Directory where the generated CCMX files will be saved.

    Returns:
        tuple[int, int]: A tuple containing the number of imported and skipped
            entries.
    """
    with open(path, "utf8") as devcorrections_file:
        lines = devcorrections_file.read().strip().splitlines()
    # Convert to JSON
    # The DeviceCorrections.txt format is as follows, so a conversion is pretty
    # straightforward:
    # "Description here, e.g. Instrument X for Monitor Y" =
    # {
    #   Name = "Description here, e.g. Instrument X for Monitor Y"
    #   Device = "Instrument X"
    #   Display = "Monitor Y"
    #   ReferenceDevice = "eye-one Pro Rev.D"
    #   MatrixXYZ = "3 3 1482250784 1.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0 "
    # }
    # "Description here, e.g. Instrument X for Monitor Y" =
    # {
    #   Name = "Description here, e.g. Instrument X for Monitor Y"
    #   Device = "Instrument X"
    #   Display = "Monitor Y"
    #   ReferenceDevice = "eye-one Pro Rev.D"
    #   MatrixXYZ = "3 3 1482250784 1.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0 "
    # }
    # ...etc.
    # NOTE: The first three numbers in MatrixXYZ are irrelevant for our purposes.
    for i, line in enumerate(lines):
        parts = line.strip().split("=")
        if len(parts) == 2:
            for j, part in enumerate(parts):
                part = part.strip()
                if part and not part.startswith('"') and not part.endswith('"'):
                    parts[j] = f'"{part}"'
        if parts[-1].strip() not in ("", "{") and i < len(lines) - 1:
            parts[-1] += ","
        lines[i] = ":".join(parts)
    devcorrections_data = "{{{}}}".format("".join(lines).replace(",}", "}"))
    # Parse JSON
    devcorrections = json.loads(devcorrections_data)
    # Convert to ccmx
    imported = 0
    skipped = 0
    for name in devcorrections:
        devcorrection = devcorrections[name]
        values = {
            "DateTime": time.strftime("%a %b %d %H:%M:%S %Y"),
            "Originator": "Quato iColorDisplay",
            "Name": "{} & {}".format(
                devcorrection.get("Device"), devcorrection.get("Display")
            ),
        }
        for key in ("Device", "Display", "ReferenceDevice", "MatrixXYZ"):
            value = devcorrection.get(key)
            if value is None:
                break
            if key == "MatrixXYZ":
                # The first three numbers in the matrix are irrelevant for our
                # purposes (see format example above).
                matrix = value.split()[3:]
                value = "\n".join(
                    [" ".join(part) for part in (matrix[0:3], matrix[3:6], matrix[6:9])]
                )
            values[key] = value
        if value is None:
            skipped += 1
            continue
        imported += 1
        with open(
            os.path.join(target_dir, f"{name}.ccmx"), "w", encoding="utf8"
        ) as ccmx:
            ccmx.write(CCMX_TEMPLATE % values)
    return imported, skipped


if __name__ == "__main__":
    convert_devicecorrections_to_ccmx(sys.argv[1], os.path.dirname(sys.argv[1]))
