from __future__ import annotations

import hashlib
import os
from pathlib import Path

from checkin_cli.weekly_operations import CustomerIdentityDigest, CustomerKey
from checkin_cli.weekly_operations_authority import (
    AuthorityId,
    WeeklyOperationsAuthorityRoot,
    begin_authority_initialization,
)
from checkin_cli.weekly_operations_layout import customer_data_name
from checkin_cli.weekly_operations_parent import acquire_parent_authority
from checkin_cli.weekly_operations_store import WeeklyOperationsStore

from nutricoach_continuity.contract import (
    OBSERVER_NAMESPACE,
    PACKAGE_ID,
    SEQUENCE_ZERO_DIGEST,
    SOURCE_FILE_DIGEST,
    SOURCE_ROW_DIGEST,
    FilePin,
    PackageContract,
    RootPin,
    package_digest,
)
from nutricoach_continuity.installed import InstalledStoreAdapter
from nutricoach_continuity.permission import PermissionPackage, RuntimeContract, finalize_permission
from nutricoach_continuity.preparation import pin_file
from nutricoach_continuity.store import ReissueOperation, source_row


class SupportError(RuntimeError):
    pass


def customer() -> CustomerKey:
    path = Path(os.environ["NUTRICOACH_TEST_CUSTOMER_KEY_FILE"])
    return CustomerKey(path.read_text(encoding="utf-8").strip())


def initialize(path: Path, authority_id: str) -> WeeklyOperationsAuthorityRoot:
    path.parent.mkdir(parents=True, exist_ok=True, mode=0o700)
    path.mkdir(mode=0o700)
    parent = acquire_parent_authority(path)
    authority: WeeklyOperationsAuthorityRoot | None = None
    with begin_authority_initialization(parent, AuthorityId(authority_id)) as transaction:
        authority = transaction.authority
        transaction.acknowledge_binding()
    if authority is None:
        raise SupportError("authority initialization")
    return authority


def root_pin(path: Path) -> RootPin:
    info = path.stat(follow_symlinks=False)
    return RootPin(
        path=path,
        device=info.st_dev,
        inode=info.st_ino,
        uid=info.st_uid,
        gid=info.st_gid,
        mode=0o700,
        nlink=info.st_nlink,
    )


def build_permission(root: Path) -> PermissionPackage:
    source_path, target_path = root / "source", root / "target"
    source_authority = initialize(source_path, "7" * 64)
    target_authority = initialize(target_path, "8" * 64)
    source_store = WeeklyOperationsStore.for_authority(source_authority, customer())
    target_store = WeeklyOperationsStore.for_authority(target_authority, customer())
    result = InstalledStoreAdapter(source_store).append(ReissueOperation(source_row()))
    assert result.appended
    assert target_store.read() == ()
    target_data = target_path / customer_data_name(
        CustomerIdentityDigest(source_row().customer_identity_digest)
    )
    descriptor = os.open(target_data, os.O_CREAT | os.O_EXCL | os.O_WRONLY, 0o600)
    os.close(descriptor)
    customer_file = root / "customer-key"
    _ = customer_file.write_text(str(customer()) + "\n", encoding="utf-8")
    customer_file.chmod(0o600)
    records: list[FilePin] = []
    for name in ("hermes.RECORD", "profile.RECORD"):
        path = root / name
        _ = path.write_text(name + "\n", encoding="utf-8")
        path.chmod(0o600)
        records.append(pin_file(path, expected_mode=0o600))
    authority_pins = tuple(
        pin_file(path, expected_mode=0o600)
        for authority in (source_path, target_path)
        for path in sorted(authority.iterdir())
    )
    closure = root / "controller-closure"
    _ = closure.write_text("sealed\n", encoding="utf-8")
    closure.chmod(0o600)
    protected = root / "protected"
    _ = protected.write_text("unchanged\n", encoding="utf-8")
    protected.chmod(0o600)
    authorization, execution = root / "authorization", root / "execution"
    draft = PackageContract.model_construct(
        schema_version="continuity-v1",
        package_id=PACKAGE_ID,
        authorization_root=authorization,
        execution_root=execution,
        observer_namespace=OBSERVER_NAMESPACE,
        source_root=root_pin(source_path),
        target_root=root_pin(target_path),
        file_pins=(pin_file(customer_file, expected_mode=0o600), *authority_pins),
        controller_closure=(pin_file(closure, expected_mode=0o600),),
        installed_records=tuple(records),
        protected_files=(pin_file(protected, expected_mode=0o600),),
        candidate_digest="a" * 64,
        sequence_zero_digest=SEQUENCE_ZERO_DIGEST,
        source_row_digest=SOURCE_ROW_DIGEST,
        expected_frame_sha256=SOURCE_FILE_DIGEST,
        zero_send_oracle_sha256=hashlib.sha256(b"zero").hexdigest(),
        package_digest="0" * 64,
    )
    contract = PackageContract.model_validate(
        {
            **draft.model_dump(mode="json", by_alias=True),
            "package_digest": package_digest(draft),
        }
    )
    baseline = root / "observer-r71" / "observations.jsonl"
    output = root / OBSERVER_NAMESPACE / "observations.jsonl"
    runtime = RuntimeContract(
        customer_key_file=customer_file,
        observer_baseline_log=baseline,
        observer_output_log=output,
        observer_timer_unit="continuity.timer",
        observer_service_unit="continuity.service",
        observer_timeout_seconds=5,
    )
    return finalize_permission(contract, runtime)
