"""Plan by default. Create ONE project in a local Disk library only after --apply.

Close/save any existing project manually first. Do not interact with Project
Manager while this script runs. There is no atomic transaction or automatic rollback.
"""
import argparse
import json

from resolve_api_connection import connect, project_manager


class CreationOutcomeError(RuntimeError):
    """A write may have happened. Inspect Resolve; never retry this blindly."""


def validate_name(name):
    # These are limits of this tutorial, not documented Resolve name limits.
    if not isinstance(name, str) or not name or name != name.strip() or len(name) > 96:
        raise ValueError("Use 1-96 characters without outer whitespace")
    if any(ord(ch) < 32 or ch in '/\\' for ch in name):
        raise ValueError("Control characters and path separators are not accepted here")
    return name


def inspect_target(manager, name):
    name = validate_name(name)
    database = manager.GetCurrentDatabase()
    if not isinstance(database, dict) or database.get("DbType") != "Disk" or not database.get("DbName"):
        raise RuntimeError("This tutorial targets a local Disk Project Library only")
    folder = manager.GetCurrentFolder()
    names = manager.GetProjectListInCurrentFolder()
    if not isinstance(folder, str) or not isinstance(names, list) or not all(isinstance(x, str) for x in names):
        raise RuntimeError("Could not read the current Project Manager folder")
    return {
        "library": database["DbName"],
        "db_type": database["DbType"],
        "folder": folder,
        "name": name,
        "name_available": name not in names,
        "project_open": bool(manager.GetCurrentProject()),
    }


def create_once(manager, name, apply=False, expected_library=None, expected_folder=None):
    before = inspect_target(manager, name)
    if not apply:
        return {"status": "plan_only", "writes": 0, "target": before}
    if expected_library is None or expected_folder is None:
        raise ValueError("--apply requires --expect-library and --expect-folder, copied from the inspected target")
    if before["library"] != expected_library or before["folder"] != expected_folder:
        raise RuntimeError("Project Library/folder differs from the explicitly expected target")
    if before["project_open"]:
        raise RuntimeError("An existing project is open. Save/close it yourself; this script will not do so.")
    if not before["name_available"]:
        raise RuntimeError("Name already exists. No LoadProject fallback is permitted.")
    # Re-read immediately before writing. This is a guard, not a lock.
    if inspect_target(manager, name) != before:
        raise RuntimeError("Project Manager state changed. No creation was attempted.")
    try:
        project = manager.CreateProject(name)
    except Exception as exc:
        raise CreationOutcomeError("CreateProject outcome unknown. Inspect Project Manager before any retry.") from exc
    if not project:
        raise CreationOutcomeError("CreateProject returned no object. No fallback, retry or deletion was attempted.")
    try:
        current = manager.GetCurrentProject()
        project_id = project.GetUniqueId()
        if not project_id or not current or current.GetUniqueId() != project_id or project.GetName() != name:
            raise CreationOutcomeError("Creation returned an object, but current-project identity is not confirmed")
        if not manager.SaveProject():
            raise CreationOutcomeError("Project was created; SaveProject did not acknowledge success. Inspect it manually.")
    except CreationOutcomeError:
        raise
    except Exception as exc:
        raise CreationOutcomeError("Creation happened; verification/save outcome is uncertain. Do not repeat creation.") from exc
    return {"status": "created_and_save_acknowledged", "target": before, "project_id": project_id}


def main(argv=None):
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("name", help="New project name; not a filesystem path")
    parser.add_argument("--apply", action="store_true", help="Allow one creation and save after all guards pass")
    parser.add_argument("--expect-library")
    parser.add_argument("--expect-folder", help="Exact folder string from plan; an empty string may represent root")
    args = parser.parse_args(argv)
    validate_name(args.name)
    result = create_once(project_manager(connect()), args.name, args.apply, args.expect_library, args.expect_folder)
    print(json.dumps(result, ensure_ascii=False, indent=2))


if __name__ == "__main__":
    main()
