#!/usr/bin/env python3
"""Convert ArgyllCMS TI1 files to i1Profiler PXF format."""

import sys
import xml.etree.ElementTree as ET
from datetime import datetime, timezone
import os

NS = "http://colorexchangeformat.com/CxF3-core"
XSI = "http://www.w3.org/2001/XMLSchema-instance"

ET.register_namespace("cc", NS)
ET.register_namespace("xsi", XSI)


def indent(elem, level=0):
    i = "\n" + "  " * level
    if len(elem):
        if not elem.text or not elem.text.strip():
            elem.text = i + "  "
        for child in elem:
            indent(child, level + 1)
        if not elem.tail or not elem.tail.strip():
            elem.tail = i
    else:
        if level and (not elem.tail or not elem.tail.strip()):
            elem.tail = i


def parse_ti1(path):
    patches = []
    in_data = False
    with open(path) as f:
        for line in f:
            line = line.strip()
            if line == "BEGIN_DATA":
                in_data = True
                continue
            if line == "END_DATA":
                break
            if in_data:
                parts = line.split()
                if len(parts) >= 4:
                    try:
                        r = float(parts[1])
                        g = float(parts[2])
                        b = float(parts[3])
                        patches.append((r, g, b))
                    except ValueError:
                        continue
    return patches


def build_pxf(patches, output_path):
    root = ET.Element(f"{{{NS}}}CxF", {f"xmlns:xsi": XSI})
    now = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
    stamp = datetime.now(timezone.utc).strftime("%Y%m%d-%H%M%S")

    file_info = ET.SubElement(root, f"{{{NS}}}FileInformation")
    ET.SubElement(file_info, f"{{{NS}}}Creator").text = f"ti1_to_pxf - {stamp}"
    ET.SubElement(file_info, f"{{{NS}}}CreationDate").text = now
    ET.SubElement(file_info, f"{{{NS}}}Description").text = f"Converted from TI1 {stamp}"

    resources = ET.SubElement(root, f"{{{NS}}}Resources")
    obj_collection = ET.SubElement(resources, f"{{{NS}}}ObjectCollection")

    for i, (r, g, b) in enumerate(patches, 1):
        clamp = lambda x: max(0, min(255, int(round(x * 2.55))))
        r255, g255, b255 = clamp(r), clamp(g), clamp(b)

        obj = ET.SubElement(obj_collection, f"{{{NS}}}Object",
                            ObjectType="Target", Name=f"Target{i}", Id=f"c{i}")
        ET.SubElement(obj, f"{{{NS}}}CreationDate").text = now
        dev = ET.SubElement(obj, f"{{{NS}}}DeviceColorValues")
        rgb = ET.SubElement(dev, f"{{{NS}}}ColorRGB", ColorSpecification="sRGB")
        ET.SubElement(rgb, f"{{{NS}}}R").text = str(r255)
        ET.SubElement(rgb, f"{{{NS}}}G").text = str(g255)
        ET.SubElement(rgb, f"{{{NS}}}B").text = str(b255)

    indent(root)

    temp_path = output_path + ".tmp"
    with open(temp_path, "wb") as f:
        ET.ElementTree(root).write(f, encoding="utf-8", xml_declaration=True)
        f.flush()
        os.fsync(f.fileno())

    with open(temp_path, "rb") as f:
        content = f.read().replace(b"\n", b"\r\n")
    with open(temp_path, "wb") as f:
        f.write(content)

    os.replace(temp_path, output_path)
    print(f"Wrote {len(patches)} patches to {output_path}")


def main():
    if len(sys.argv) < 2:
        print("Usage: ti1_to_pxf.py input.ti1 [output.pxf]")
        sys.exit(1)

    input_path = sys.argv[1]
    if len(sys.argv) > 2:
        output_path = sys.argv[2]
    else:
        output_path = input_path.rsplit(".", 1)[0] + ".pxf"

    patches = parse_ti1(input_path)
    if not patches:
        print("No patches found in TI1 file.")
        sys.exit(1)
    print(f"Read {len(patches)} patches from {input_path}")
    build_pxf(patches, output_path)


if __name__ == "__main__":
    main()
