import type {
  TmpaCoreVersion,
  TmpaLifecycleProfile,
  TmpaVersionedInput,
} from "@codeflowmu/protocol";

import {
  CODEFLOWMU_TMPA_CANONICALIZATION_PROFILE,
  CODEFLOWMU_TMPA_S06_CANONICALIZATION_PROFILE,
  canonicalBytes,
  compareUnicodeCodePoints,
  sha256Digest,
} from "./canonical.ts";

export interface TmpaRoleAssignment {
  identity: string;
  role: string;
  actions: string[];
}

export interface CodeFlowMuTmpaProfileOptions {
  assignments?: TmpaRoleAssignment[];
  coreVersion?: TmpaCoreVersion;
}

const DOCUMENT_TYPES = [
  "TASK",
  "TRANSITION",
  "STATE_OBSERVATION",
  "REPORT",
  "REVIEW",
  "DECISION",
  "CORRECTION",
  "ISSUE",
  "FAILURE",
  "RECOVERY",
  "INSPECTION",
  "ALERT",
] as const;

const ORDERING_RELATIONS = [
  "depends_on",
  "reports",
  "responds_to",
  "reviews",
  "accepts",
  "human_approves",
  "archives",
  "parent",
] as const;

export function createCodeFlowMuTmpaProfile(
  options: CodeFlowMuTmpaProfileOptions = {},
): TmpaLifecycleProfile {
  const coreVersion = options.coreVersion ?? "S1.0";
  const assignments = [
    {
      identity: "CODEFLOWMU-RUNTIME",
      role: "SYSTEM",
      actions: ["runtime_dispatch", "runtime_restore_failed_dispatch"],
    },
    {
      identity: "human:ADMIN",
      role: "ADMIN",
      actions: [
        "approve_review",
        "reject_review",
        "resolve_review_conflict",
        "reopen_task",
        "archive_task",
        "force_archive_task",
      ],
    },
    ...(options.assignments ?? []),
  ].sort((left, right) =>
    compareUnicodeCodePoints(
      `${left.identity}\u0000${left.role}`,
      `${right.identity}\u0000${right.role}`,
    ),
  );

  return {
    id: `codeflowmu-fcop-tmpa-${coreVersion.toLowerCase()}`,
    version: coreVersion === "S0.5" ? "1.0.1" : "1.1.0",
    states: ["inbox", "active", "review", "done", "archive"],
    initial_state: "inbox",
    terminal_states: ["archive"],
    actions: [
      "runtime_dispatch",
      "submit_review",
      "approve_review",
      "reject_review",
      "resolve_review_conflict",
      "reopen_task",
      "archive_task",
      "force_archive_task",
      "runtime_restore_failed_dispatch",
    ],
    transitions: [
      {
        from: "inbox",
        action: "runtime_dispatch",
        to: "active",
        allowed_roles: ["SYSTEM", "PM"],
        required_relations: [],
      },
      {
        from: "active",
        action: "submit_review",
        to: "review",
        allowed_roles: ["PM", "DEV", "QA", "OPS"],
        required_relations: ["reports"],
      },
      {
        from: "review",
        action: "approve_review",
        to: "done",
        allowed_roles: ["ADMIN", "PM", "QA"],
        required_relations: ["accepts"],
        separation_of_duties: ["executor_must_not_approve"],
      },
      {
        from: "review",
        action: "reject_review",
        to: "active",
        allowed_roles: ["ADMIN", "PM", "QA"],
        required_relations: [],
      },
      {
        from: "done",
        action: "reopen_task",
        to: "active",
        allowed_roles: ["ADMIN", "PM"],
        required_relations: [],
      },
      {
        from: "active",
        action: "force_archive_task",
        to: "archive",
        allowed_roles: ["ADMIN", "PM"],
        required_relations: [],
      },
      {
        from: "review",
        action: "force_archive_task",
        to: "archive",
        allowed_roles: ["ADMIN", "PM"],
        required_relations: [],
      },
      {
        from: "active",
        action: "runtime_restore_failed_dispatch",
        to: "inbox",
        allowed_roles: ["SYSTEM"],
        required_relations: [],
      },
      {
        from: "done",
        action: "archive_task",
        to: "archive",
        allowed_roles: ["ADMIN", "PM"],
        required_relations: [],
      },
    ],
    recovery_rules: [
      "source_history_is_preserved",
      "reader_requires_no_hidden_chain_of_thought",
    ],
    acceptance: {
      states_requiring_acceptance: ["done", "archive"],
      acceptance_relations: ["accepts"],
      allowed_roles: ["ADMIN", "PM", "QA"],
      requires_independent_actor: true,
      archive_requires_acceptance: true,
    },
    work_graph: {
      completion_claim_predicates: ["work.complete", "delivery.complete"],
      response_relations: ["reports", "responds_to"],
      child_terminal_states: ["done", "archive"],
    },
    risk_policy: {
      human_approval_levels: ["high", "irreversible"],
      approval_relations: ["human_approves"],
      approval_roles: ["ADMIN"],
      ...(coreVersion !== "S0.5"
        ? {
            approval_object_types: ["DECISION"],
            requires_independent_actor: true,
          }
        : {}),
    },
    failure_model: {
      failure_types: ["timeout", "crash", "deadlock", "drift"],
      recovery_actions: ["retry", "resume", "rollback", "abort", "escalate"],
    },
    extensions: {
      document_types: [...DOCUMENT_TYPES],
      assignments,
      ordering_relations: [...ORDERING_RELATIONS],
      acyclic_relations: ["depends_on", "parent"],
      review_conflict_resolution: {
        action: "resolve_review_conflict",
        allowed_roles: ["ADMIN", "PM", "QA"],
        resolution_relation: "resolves",
        selection_field: "selects",
      },
      source_profile: "FCoP 3.x project-visible filesystem",
    },
  };
}

function versionedInput(id: string, version: string, value: unknown): TmpaVersionedInput {
  return { id, version, digest: sha256Digest(canonicalBytes(value)) };
}

export function createTmpaProfileBundle(
  profile: TmpaLifecycleProfile,
  coreVersion: TmpaCoreVersion = "S1.0",
) {
  const documentTypes = profile.extensions?.document_types ?? [];
  const assignments = profile.extensions?.assignments ?? [];
  const relations = {
    ordering: profile.extensions?.ordering_relations ?? [],
    acyclic: profile.extensions?.acyclic_relations ?? [],
  };
  const integrity = {
    algorithm: "sha256",
    signature_policy: "optional-unverified-is-undetermined",
  };
  const canonicalization =
    coreVersion === "S1.0"
      ? CODEFLOWMU_TMPA_CANONICALIZATION_PROFILE
      : coreVersion === "S0.6"
        ? CODEFLOWMU_TMPA_S06_CANONICALIZATION_PROFILE
        : {
          id: "codeflowmu-tmpa-s0.5-json-v1",
          object_keys: "unicode-codepoint-ascending",
          arrays: "semantic-order-preserved",
          encoding: "utf-8",
          trailing_newline: true,
        };

  return {
    conformance_profile: versionedInput(profile.id, profile.version, profile),
    object_schema: {
      id: `urn:tmpa:schema:governance-object:${coreVersion.toLowerCase()}`,
      version: coreVersion,
      digest:
        coreVersion === "S1.0"
          ? "sha256:a2829cd7149c3054a52886365f2293a23106b636b0c52799739bfabdab1ff4fa"
          : coreVersion === "S0.6"
            ? "sha256:623fd1d639defa441353993a3f5c1b228889d8977f5ac199d05c23f4683d036b"
            : "sha256:b2a282b59b9cf2c431db0e1fbb2b405485315f2a2b90739858e669c5e59633d5",
    },
    type_registry: versionedInput("codeflowmu-tmpa-types", "1.0.0", documentTypes),
    lifecycle_registry: versionedInput(profile.id, profile.version, profile),
    role_registry: versionedInput("codeflowmu-team-roles", "1.0.0", assignments),
    relation_registry: versionedInput("codeflowmu-fcop-relations", "1.0.0", relations),
    integrity_profile: versionedInput("codeflowmu-tmpa-integrity", "1.0.0", integrity),
    canonicalization_profile: versionedInput(
      canonicalization.id,
      "version" in canonicalization ? canonicalization.version : "1.0.0",
      canonicalization,
    ),
  };
}
