#!/usr/bin/env python3
"""XML-выгрузка ВНЕШНЕЙ обработки/отчёта → объект расширения конфигурации.

Меняются только метаданные (XML). Модули .bsl копируются байт-в-байт —
иначе проверялся бы не тот код, который уходит пользователю.

Использование: ext_wrap.py <каталог-выгрузки> <каталог-расширения> [имя-расш]
"""
import re
import shutil
import sys
from pathlib import Path

CLASS_IDS = [
    "9cd510cd-abfc-11d4-9434-004095e12fc7",
    "9fcd25a0-4822-11d4-9414-008048da11f9",
    "e3687481-0a87-462c-a166-9f34594f9bba",
    "9de14907-ec23-4a07-96f0-85521cb6b53b",
    "51f2d5d8-ea4d-4064-8892-82951750031e",
    "e68182ea-4237-4383-967f-90c1e3370bc7",
    "fb282519-d103-4dd3-bc12-cb271d631dfc",
]

NS = ('xmlns="http://v8.1c.ru/8.3/MDClasses" '
      'xmlns:app="http://v8.1c.ru/8.2/managed-application/core" '
      'xmlns:cfg="http://v8.1c.ru/8.1/data/enterprise/current-config" '
      'xmlns:ent="http://v8.1c.ru/8.1/data/enterprise" '
      'xmlns:lf="http://v8.1c.ru/8.2/managed-application/logform" '
      'xmlns:v8="http://v8.1c.ru/8.1/data/core" '
      'xmlns:v8ui="http://v8.1c.ru/8.1/data/ui" '
      'xmlns:xen="http://v8.1c.ru/8.3/xcf/enums" '
      'xmlns:xpr="http://v8.1c.ru/8.3/xcf/predef" '
      'xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" '
      'xmlns:xs="http://www.w3.org/2001/XMLSchema" '
      'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.20"')

# Детерминированные uuid: одна и та же обработка → одно и то же расширение,
# повторный прогон не плодит мусор в базе.
def det_uuid(seed: str, tag: int) -> str:
    import hashlib
    h = hashlib.md5(f"{seed}|{tag}".encode()).hexdigest()
    return f"{h[:8]}-{h[8:12]}-4{h[13:16]}-8{h[17:20]}-{h[20:32]}"


def wrap(src_dir: Path, out_dir: Path, ext_name: str = "аСтенд") -> dict:
    roots = [p for p in src_dir.iterdir()
             if p.suffix.lower() == ".xml" and (src_dir / p.stem).is_dir()]
    if len(roots) != 1:
        raise SystemExit(f"ожидался один корневой XML, нашёл {len(roots)}")
    root_xml = roots[0]
    body_dir = src_dir / root_xml.stem
    text = root_xml.read_text(encoding="utf-8-sig")

    if "<ExternalDataProcessor " in text:
        src_kind, dst_kind, coll = ("ExternalDataProcessor", "DataProcessor",
                                    "DataProcessors")
    elif "<ExternalReport " in text:
        src_kind, dst_kind, coll = "ExternalReport", "Report", "Reports"
    else:
        raise SystemExit("корневой XML — не внешняя обработка и не внешний отчёт")

    name = re.search(r"<Name>([^<]+)</Name>", text).group(1)

    # 1. тип объекта
    text = text.replace(f"<{src_kind} ", f"<{dst_kind} ", 1)
    text = text.replace(f"</{src_kind}>", f"</{dst_kind}>")

    # 2. InternalInfo внешнего объекта (ContainedObject) → GeneratedType,
    #    как у объекта конфигурации
    gen = (
        f'<InternalInfo>\n'
        f'\t\t\t<xr:GeneratedType name="{dst_kind}Object.{name}" '
        f'category="Object">\n'
        f'\t\t\t\t<xr:TypeId>{det_uuid(name, 1)}</xr:TypeId>\n'
        f'\t\t\t\t<xr:ValueId>{det_uuid(name, 2)}</xr:ValueId>\n'
        f'\t\t\t</xr:GeneratedType>\n'
        f'\t\t\t<xr:GeneratedType name="{dst_kind}Manager.{name}" '
        f'category="Manager">\n'
        f'\t\t\t\t<xr:TypeId>{det_uuid(name, 3)}</xr:TypeId>\n'
        f'\t\t\t\t<xr:ValueId>{det_uuid(name, 4)}</xr:ValueId>\n'
        f'\t\t\t</xr:GeneratedType>\n'
        f'\t\t</InternalInfo>')
    text = re.sub(r"<InternalInfo>.*?</InternalInfo>", gen, text,
                  count=1, flags=re.S)

    # 3. Properties: принадлежность расширению + обязательные поля объекта
    #    конфигурации, которых у внешней обработки нет
    text = text.replace("<Properties>",
                        "<Properties>\n\t\t\t<ObjectBelonging>Native"
                        "</ObjectBelonging>", 1)
    if "<UseStandardCommands>" not in text.split("<ChildObjects>")[0]:
        text = re.sub(r"(<Comment>[^<]*</Comment>|<Comment/>)",
                      r"\1\n\t\t\t<UseStandardCommands>true"
                      r"</UseStandardCommands>", text, count=1)
    head, sep, tail = text.partition("<ChildObjects>")
    if "<IncludeHelpInContents>" not in head:
        head = head.replace(
            "<AuxiliaryForm/>",
            "<AuxiliaryForm/>\n\t\t\t<IncludeHelpInContents>false"
            "</IncludeHelpInContents>\n\t\t\t<ExtendedPresentation/>"
            "\n\t\t\t<Explanation/>", 1)
    text = head + sep + tail

    # 4. ссылки на тип: ExternalDataProcessor.X.Form.Y → DataProcessor.X.Form.Y
    text = text.replace(f"{src_kind}.{name}.", f"{dst_kind}.{name}.")

    # 5. раскладка
    if out_dir.exists():
        shutil.rmtree(out_dir)
    (out_dir / coll).mkdir(parents=True)
    (out_dir / coll / f"{name}.xml").write_text(text, encoding="utf-8-sig")
    shutil.copytree(body_dir, out_dir / coll / name)

    # 6. в описаниях форм — тип реквизита «Объект»
    for form_xml in (out_dir / coll / name).rglob("*.xml"):
        t = form_xml.read_text(encoding="utf-8-sig", errors="replace")
        if f"{src_kind}Object." in t:
            form_xml.write_text(
                t.replace(f"{src_kind}Object.", f"{dst_kind}Object."),
                encoding="utf-8-sig")

    internal = "\n".join(
        f"\t\t\t<xr:ContainedObject>\n"
        f"\t\t\t\t<xr:ClassId>{c}</xr:ClassId>\n"
        f"\t\t\t\t<xr:ObjectId>{det_uuid(ext_name, 100 + i)}</xr:ObjectId>\n"
        f"\t\t\t</xr:ContainedObject>"
        for i, c in enumerate(CLASS_IDS))
    conf = f'''<?xml version="1.0" encoding="UTF-8"?>
<MetaDataObject {NS}>
	<Configuration uuid="{det_uuid(ext_name, 0)}">
		<InternalInfo>
{internal}
		</InternalInfo>
		<Properties>
			<ObjectBelonging>Adopted</ObjectBelonging>
			<Name>{ext_name}</Name>
			<Synonym>
				<v8:item>
					<v8:lang>ru</v8:lang>
					<v8:content>Стенд проверки</v8:content>
				</v8:item>
			</Synonym>
			<Comment/>
			<NamePrefix/>
			<ConfigurationExtensionCompatibilityMode>Version8_3_27</ConfigurationExtensionCompatibilityMode>
			<ConfigurationExtensionPurpose>Customization</ConfigurationExtensionPurpose>
			<DefaultRunMode>ManagedApplication</DefaultRunMode>
			<UsePurposes>
				<v8:Value xsi:type="app:ApplicationUsePurpose">PlatformApplication</v8:Value>
			</UsePurposes>
			<ScriptVariant>Russian</ScriptVariant>
			<Vendor>cebers</Vendor>
			<Version>1.0.0.1</Version>
		</Properties>
		<ChildObjects>
			<{dst_kind}>{name}</{dst_kind}>
		</ChildObjects>
	</Configuration>
</MetaDataObject>
'''
    (out_dir / "Configuration.xml").write_text(conf, encoding="utf-8-sig")
    return {"name": name, "kind": dst_kind, "collection": coll}


if __name__ == "__main__":
    info = wrap(Path(sys.argv[1]).resolve(), Path(sys.argv[2]).resolve(),
                sys.argv[3] if len(sys.argv) > 3 else "аСтенд")
    print(f"{info['kind']}.{info['name']} → {sys.argv[2]}")
