/**
 * Shared Model Contract Layer
 *
 * 单一字段定义源（Single Source of Truth）。
 * 所有 agent 通过 import { createContract } from "./model-contract.mjs" 引用，
 * 禁止自行定义任何字段名。
 *
 * 提供：
 *   - entities[]          — 所有实体的字段定义（PascalCase 名 + snake_case 表名）
 *   - auth{}              — 认证配置
 *   - permissions[]       — RBAC 权限矩阵
 *   - fieldMapping{}      — snake_case ↔ camelCase 双向映射
 *   - validation{}        — 字段级校验规则
 */

// ═══════════════════════════════════════════════════════
// 1. Domain-Specific Entity Templates
// ═══════════════════════════════════════════════════════

/**
 * Base entity templates for common domains.
 * These are the canonical field definitions for every entity.
 * Key: domain name → Array of entity templates.
 */
const DOMAIN_ENTITIES = {
  enterprise: [
    {
      name: "User",
      table: "users",
      description: "系统用户",
      fields: [
        { name: "id", type: "UUID", isPrimary: true, isAuto: true },
        { name: "username", type: "VARCHAR(128)", required: true, unique: true, validation: { minLength: 2, maxLength: 50 } },
        { name: "password_hash", type: "VARCHAR(256)", required: true, isSecret: true },
        { name: "nickname", type: "VARCHAR(128)" },
        { name: "role", type: "VARCHAR(32)", defaultValue: "user", enum: ["user", "admin"] },
        { name: "phone", type: "VARCHAR(20)" },
        { name: "avatar_url", type: "TEXT" },
        { name: "created_at", type: "TIMESTAMP", isAuto: true },
        { name: "updated_at", type: "TIMESTAMP", isAuto: true },
      ],
      relationships: [
        { type: "hasMany", entity: "contracts", via: "user_id" },
        { type: "hasMany", entity: "customers", via: "user_id" },
      ],
    },
    {
      name: "Contract",
      table: "contracts",
      description: "合同",
      fields: [
        { name: "id", type: "UUID", isPrimary: true, isAuto: true },
        { name: "user_id", type: "UUID", required: true, fkEntity: "users", fkColumn: "id" },
        { name: "title", type: "VARCHAR(256)", required: true },
        { name: "party_a", type: "VARCHAR(128)" },
        { name: "party_b", type: "VARCHAR(128)" },
        { name: "amount", type: "DECIMAL(14,2)" },
        { name: "signed_at", type: "DATE" },
        { name: "expires_at", type: "DATE" },
        { name: "status", type: "VARCHAR(32)", defaultValue: "draft", enum: ["draft", "pending", "active", "expired", "terminated"] },
        { name: "file_url", type: "TEXT" },
        { name: "created_at", type: "TIMESTAMP", isAuto: true },
        { name: "updated_at", type: "TIMESTAMP", isAuto: true },
      ],
      relationships: [
        { type: "belongsTo", entity: "users", via: "user_id" },
      ],
    },
    {
      name: "Approval",
      table: "approvals",
      description: "审批流程",
      fields: [
        { name: "id", type: "UUID", isPrimary: true, isAuto: true },
        { name: "user_id", type: "UUID", required: true, fkEntity: "users", fkColumn: "id" },
        { name: "entity_type", type: "VARCHAR(32)", required: true },
        { name: "entity_id", type: "UUID" },
        { name: "applicant_id", type: "UUID", required: true, fkEntity: "users", fkColumn: "id" },
        { name: "status", type: "VARCHAR(32)", defaultValue: "pending", enum: ["pending", "approved", "rejected"] },
        { name: "form_data", type: "JSONB" },
        { name: "created_at", type: "TIMESTAMP", isAuto: true },
        { name: "updated_at", type: "TIMESTAMP", isAuto: true },
      ],
      relationships: [
        { type: "belongsTo", entity: "users", via: "user_id" },
        { type: "belongsTo", entity: "users", via: "applicant_id", as: "applicant" },
      ],
    },
    {
      name: "Customer",
      table: "customers",
      description: "客户",
      fields: [
        { name: "id", type: "UUID", isPrimary: true, isAuto: true },
        { name: "user_id", type: "UUID", required: true, fkEntity: "users", fkColumn: "id" },
        { name: "name", type: "VARCHAR(128)", required: true },
        { name: "email", type: "VARCHAR(256)" },
        { name: "phone", type: "VARCHAR(20)" },
        { name: "company", type: "VARCHAR(128)" },
        { name: "source", type: "VARCHAR(64)" },
        { name: "tags", type: "JSONB", defaultValue: "[]" },
        { name: "created_at", type: "TIMESTAMP", isAuto: true },
        { name: "updated_at", type: "TIMESTAMP", isAuto: true },
      ],
      relationships: [
        { type: "belongsTo", entity: "users", via: "user_id" },
      ],
    },
    {
      name: "Reminder",
      table: "reminders",
      description: "到期提醒",
      fields: [
        { name: "id", type: "UUID", isPrimary: true, isAuto: true },
        { name: "user_id", type: "UUID", required: true, fkEntity: "users", fkColumn: "id" },
        { name: "entity_type", type: "VARCHAR(32)", required: true },
        { name: "entity_id", type: "UUID" },
        { name: "remind_at", type: "TIMESTAMP", required: true },
        { name: "message", type: "TEXT" },
        { name: "sent", type: "BOOLEAN", defaultValue: "false" },
        { name: "created_at", type: "TIMESTAMP", isAuto: true },
        { name: "updated_at", type: "TIMESTAMP", isAuto: true },
      ],
      relationships: [
        { type: "belongsTo", entity: "users", via: "user_id" },
      ],
    },
  ],

  pet: [
    {
      name: "User",
      table: "users",
      description: "系统用户",
      fields: [
        { name: "id", type: "UUID", isPrimary: true, isAuto: true },
        { name: "username", type: "VARCHAR(128)", required: true, unique: true, validation: { minLength: 2, maxLength: 50 } },
        { name: "password_hash", type: "VARCHAR(256)", required: true, isSecret: true },
        { name: "nickname", type: "VARCHAR(128)" },
        { name: "role", type: "VARCHAR(32)", defaultValue: "user", enum: ["user", "admin"] },
        { name: "phone", type: "VARCHAR(20)" },
        { name: "avatar_url", type: "TEXT" },
        { name: "created_at", type: "TIMESTAMP", isAuto: true },
        { name: "updated_at", type: "TIMESTAMP", isAuto: true },
      ],
      relationships: [],
    },
    {
      name: "Pet",
      table: "pets",
      description: "宠物",
      fields: [
        { name: "id", type: "UUID", isPrimary: true, isAuto: true },
        { name: "user_id", type: "UUID", required: true, fkEntity: "users", fkColumn: "id" },
        { name: "name", type: "VARCHAR(64)", required: true },
        { name: "species", type: "VARCHAR(32)" },
        { name: "breed", type: "VARCHAR(64)" },
        { name: "birth_date", type: "DATE" },
        { name: "weight_kg", type: "DECIMAL(5,2)" },
        { name: "avatar_url", type: "TEXT" },
        { name: "created_at", type: "TIMESTAMP", isAuto: true },
        { name: "updated_at", type: "TIMESTAMP", isAuto: true },
      ],
      relationships: [
        { type: "belongsTo", entity: "users", via: "user_id" },
      ],
    },
  ],

  ecommerce: [
    {
      name: "User",
      table: "users",
      description: "系统用户",
      fields: [
        { name: "id", type: "UUID", isPrimary: true, isAuto: true },
        { name: "username", type: "VARCHAR(128)", required: true, unique: true, validation: { minLength: 2, maxLength: 50 } },
        { name: "password_hash", type: "VARCHAR(256)", required: true, isSecret: true },
        { name: "nickname", type: "VARCHAR(128)" },
        { name: "role", type: "VARCHAR(32)", defaultValue: "user", enum: ["user", "admin"] },
        { name: "phone", type: "VARCHAR(20)" },
        { name: "avatar_url", type: "TEXT" },
        { name: "created_at", type: "TIMESTAMP", isAuto: true },
        { name: "updated_at", type: "TIMESTAMP", isAuto: true },
      ],
      relationships: [],
    },
    {
      name: "Product",
      table: "products",
      description: "商品",
      fields: [
        { name: "id", type: "UUID", isPrimary: true, isAuto: true },
        { name: "user_id", type: "UUID", required: true, fkEntity: "users", fkColumn: "id" },
        { name: "title", type: "VARCHAR(256)", required: true },
        { name: "description", type: "TEXT" },
        { name: "price", type: "DECIMAL(10,2)" },
        { name: "stock", type: "INTEGER", defaultValue: "0" },
        { name: "images", type: "JSONB", defaultValue: "[]" },
        { name: "created_at", type: "TIMESTAMP", isAuto: true },
        { name: "updated_at", type: "TIMESTAMP", isAuto: true },
      ],
      relationships: [
        { type: "belongsTo", entity: "users", via: "user_id" },
      ],
    },
    {
      name: "Order",
      table: "orders",
      description: "订单",
      fields: [
        { name: "id", type: "UUID", isPrimary: true, isAuto: true },
        { name: "user_id", type: "UUID", required: true, fkEntity: "users", fkColumn: "id" },
        { name: "status", type: "VARCHAR(32)", defaultValue: "pending", enum: ["pending", "paid", "shipped", "delivered", "cancelled"] },
        { name: "total_amount", type: "DECIMAL(12,2)" },
        { name: "address_id", type: "UUID", fkEntity: "addresses", fkColumn: "id" },
        { name: "created_at", type: "TIMESTAMP", isAuto: true },
        { name: "updated_at", type: "TIMESTAMP", isAuto: true },
      ],
      relationships: [
        { type: "belongsTo", entity: "users", via: "user_id" },
      ],
    },
  ],

  education: [
    {
      name: "User",
      table: "users",
      description: "系统用户",
      fields: [
        { name: "id", type: "UUID", isPrimary: true, isAuto: true },
        { name: "username", type: "VARCHAR(128)", required: true, unique: true, validation: { minLength: 2, maxLength: 50 } },
        { name: "password_hash", type: "VARCHAR(256)", required: true, isSecret: true },
        { name: "nickname", type: "VARCHAR(128)" },
        { name: "role", type: "VARCHAR(32)", defaultValue: "user", enum: ["user", "admin", "instructor"] },
        { name: "phone", type: "VARCHAR(20)" },
        { name: "avatar_url", type: "TEXT" },
        { name: "created_at", type: "TIMESTAMP", isAuto: true },
        { name: "updated_at", type: "TIMESTAMP", isAuto: true },
      ],
      relationships: [],
    },
  ],

  note: [
    {
      name: "User",
      table: "users",
      description: "系统用户",
      fields: [
        { name: "id", type: "UUID", isPrimary: true, isAuto: true },
        { name: "username", type: "VARCHAR(128)", required: true, unique: true, validation: { minLength: 2, maxLength: 50 } },
        { name: "password_hash", type: "VARCHAR(256)", required: true, isSecret: true },
        { name: "nickname", type: "VARCHAR(128)" },
        { name: "role", type: "VARCHAR(32)", defaultValue: "user", enum: ["user", "admin"] },
        { name: "phone", type: "VARCHAR(20)" },
        { name: "avatar_url", type: "TEXT" },
        { name: "created_at", type: "TIMESTAMP", isAuto: true },
        { name: "updated_at", type: "TIMESTAMP", isAuto: true },
      ],
      relationships: [],
    },
  ],

  fitness: [
    {
      name: "User",
      table: "users",
      description: "系统用户",
      fields: [
        { name: "id", type: "UUID", isPrimary: true, isAuto: true },
        { name: "username", type: "VARCHAR(128)", required: true, unique: true, validation: { minLength: 2, maxLength: 50 } },
        { name: "password_hash", type: "VARCHAR(256)", required: true, isSecret: true },
        { name: "nickname", type: "VARCHAR(128)" },
        { name: "role", type: "VARCHAR(32)", defaultValue: "user", enum: ["user", "admin"] },
        { name: "phone", type: "VARCHAR(20)" },
        { name: "avatar_url", type: "TEXT" },
        { name: "created_at", type: "TIMESTAMP", isAuto: true },
        { name: "updated_at", type: "TIMESTAMP", isAuto: true },
      ],
      relationships: [],
    },
  ],
};

// ═══════════════════════════════════════════════════════
// 2. Field Mapping Engine
// ═══════════════════════════════════════════════════════

/**
 * Build bidirectional snake_case ↔ camelCase mappings from all contract entities.
 * Scanned once; cached in the returned contract.
 */
function buildFieldMappings(entities) {
  const snakeToCamel = {};
  const camelToSnake = {};

  // Base conversions from common SQL columns
  const baseMappings = {
    snakeToCamel: {
      "created_at": "createdAt",
      "updated_at": "updatedAt",
      "user_id": "userId",
    },
    camelToSnake: {
      "createdAt": "created_at",
      "updatedAt": "updated_at",
      "userId": "user_id",
    },
  };

  Object.assign(snakeToCamel, baseMappings.snakeToCamel);
  Object.assign(camelToSnake, baseMappings.camelToSnake);

  for (const entity of entities) {
    for (const field of entity.fields) {
      const snake = field.name; // fields are stored in snake_case
      // Convert to camelCase
      const camel = snake.replace(/_([a-z])/g, (_, c) => c.toUpperCase());

      if (snake !== camel) {
        snakeToCamel[snake] = camel;
        camelToSnake[camel] = snake;
      }
    }
  }

  // Add common patterns
  const known = [
    ["id", "id"],
    ["username", "username"],
    ["password_hash", "passwordHash"],
    ["nickname", "nickname"],
    ["role", "role"],
    ["phone", "phone"],
    ["avatar_url", "avatarUrl"],
    ["title", "title"],
    ["description", "description"],
    ["status", "status"],
    ["data", "data"],
    ["amount", "amount"],
    ["party_a", "partyA"],
    ["party_b", "partyB"],
    ["signed_at", "signedAt"],
    ["expires_at", "expiresAt"],
    ["file_url", "fileUrl"],
    ["entity_type", "entityType"],
    ["entity_id", "entityId"],
    ["applicant_id", "applicantId"],
    ["form_data", "formData"],
    ["name", "name"],
    ["email", "email"],
    ["company", "company"],
    ["source", "source"],
    ["tags", "tags"],
    ["breed", "breed"],
    ["species", "species"],
    ["birth_date", "birthDate"],
    ["weight_kg", "weightKg"],
    ["price", "price"],
    ["stock", "stock"],
    ["images", "images"],
    ["total_amount", "totalAmount"],
    ["address_id", "addressId"],
    ["remind_at", "remindAt"],
    ["message", "message"],
    ["sent", "sent"],
  ];

  for (const [snake, camel] of known) {
    if (!snakeToCamel[snake]) snakeToCamel[snake] = camel;
    if (!camelToSnake[camel]) camelToSnake[camel] = snake;
  }

  return { snakeToCamel, camelToSnake };
}

// ═══════════════════════════════════════════════════════
// 3. Auth Configuration
// ═══════════════════════════════════════════════════════

function buildAuthConfig(domain) {
  // Enterprise domain has stricter auth
  const isEnterprise = domain === "enterprise";

  return {
    registrationFields: ["username", "password", "nickname"],
    loginFields: ["username", "password"],
    jwtPayload: ["userId", "username", "role"],
    passwordPolicy: {
      minLength: isEnterprise ? 8 : 6,
      requireSpecial: isEnterprise,
    },
  };
}

// ═══════════════════════════════════════════════════════
// 4. Permissions Matrix
// ═══════════════════════════════════════════════════════

function buildPermissions(domain) {
  return [
    { role: "admin", allow: ["*"] },
    { role: "user", allow: ["read:own", "create:*", "update:own", "delete:own"] },
  ];
}

// ═══════════════════════════════════════════════════════
// 5. Validation Rules
// ═══════════════════════════════════════════════════════

function buildValidation(entities) {
  const rules = {};

  for (const entity of entities) {
    const fieldRules = {};
    for (const field of entity.fields) {
      if (field.validation) {
        fieldRules[field.name] = { ...field.validation };
      }
      // Auto-generate from field properties
      if (field.required || field.unique || field.enum || field.defaultValue !== undefined) {
        if (!fieldRules[field.name]) fieldRules[field.name] = {};
      }
      if (field.required) {
        fieldRules[field.name].required = true;
      }
      if (field.unique) {
        fieldRules[field.name].unique = true;
      }
      if (field.enum) {
        fieldRules[field.name].enum = field.enum;
      }
      if (field.defaultValue !== undefined) {
        fieldRules[field.name].defaultValue = field.defaultValue;
      }
    }
    if (Object.keys(fieldRules).length > 0) {
      rules[entity.name] = fieldRules;
    }
  }

  return rules;
}

// ═══════════════════════════════════════════════════════
// 6. Main Contract Builder
// ═══════════════════════════════════════════════════════

/**
 * Create a Model Contract from PRD and Architecture.
 *
 * The contract is the SINGLE SOURCE OF TRUTH for all entity field definitions.
 * All generators MUST read from the contract; they MUST NOT invent field names.
 *
 * @param {object} prd — PRD from SF-01 (project-intake-agent)
 * @param {object} arch — Architecture from SF-02 (architecture-agent), optional
 * @returns {object} Contract object
 */
export function createContract(prd, arch) {
  const domain = (prd && prd.domain) || (arch && arch.domain) || "generic";
  const projectName = (prd && prd.projectName) || (arch && arch.projectName) || "App";

  // ── Get domain-specific entities ──
  let entities = DOMAIN_ENTITIES[domain] || DOMAIN_ENTITIES.enterprise;

  // Deep clone to avoid mutation
  entities = JSON.parse(JSON.stringify(entities));

  // ── Augment with domain-specific entities from features/APIs ──
  // If architecture has derived tables, merge them into the contract
  if (arch && arch.databaseSchema) {
    const existingTables = new Set(entities.map(e => e.table));
    const existingNames = new Set(entities.map(e => e.name));

    for (const table of arch.databaseSchema) {
      if (!existingTables.has(table.table) && table.table !== "users") {
        // Auto-generate PascalCase entity name from snake_case table
        const pascalName = table.table
          .split("_")
          .map(w => w.charAt(0).toUpperCase() + w.slice(1))
          .join("");

        if (!existingNames.has(pascalName)) {
          const entity = {
            name: pascalName,
            table: table.table,
            description: table.description || `${pascalName}表`,
            fields: (table.fields || []).map(f => ({
              name: f.name,
              type: f.type || "TEXT",
              required: (f.constraints || "").includes("NOT NULL") || (f.constraints || "").includes("PK"),
              isPrimary: (f.constraints || "").includes("PK"),
              isAuto: f.name === "created_at" || f.name === "updated_at" || (f.constraints || "").includes("DEFAULT"),
              ...((f.constraints || "").includes("UNIQUE") ? { unique: true } : {}),
              ...((f.constraints || "").includes("FK") ? {
                fkEntity: (f.name.endsWith("_id") ? f.name.replace(/_id$/, "s") : "items"),
                fkColumn: "id",
              } : {}),
            })),
            relationships: [],
          };

          // Run FK detection on fields
          for (const field of entity.fields) {
            if (field.fkEntity) {
              entity.relationships.push({
                type: "belongsTo",
                entity: field.fkEntity,
                via: field.name,
              });
            }
          }

          entities.push(entity);
          existingTables.add(table.table);
          existingNames.add(pascalName);
        }
      }
    }
  }

  // ── Build mappings ──
  const fieldMapping = buildFieldMappings(entities);
  const auth = buildAuthConfig(domain);
  const permissions = buildPermissions(domain);
  const validation = buildValidation(entities);

  return {
    projectName,
    domain,
    entities,
    auth,
    permissions,
    fieldMapping,
    validation,
  };
}

// ═══════════════════════════════════════════════════════
// 7. Contract Utility Functions
// ═══════════════════════════════════════════════════════

/**
 * Look up a field in the contract by entity.table and field name (snake_case).
 *
 * @param {object} contract
 * @param {string} tableName — snake_case table name
 * @param {string} fieldName — snake_case field name
 * @returns {object|null} Field definition
 */
export function lookupField(contract, tableName, fieldName) {
  for (const entity of contract.entities) {
    if (entity.table === tableName) {
      return entity.fields.find(f => f.name === fieldName) || null;
    }
  }
  return null;
}

/**
 * Get the camelCase name for a snake_case column from the contract's fieldMapping.
 *
 * @param {object} contract
 * @param {string} snakeName
 * @returns {string}
 */
export function toCamel(contract, snakeName) {
  return contract.fieldMapping.snakeToCamel[snakeName] || snakeName;
}

/**
 * Get the snake_case name for a camelCase property from the contract's fieldMapping.
 *
 * @param {object} contract
 * @param {string} camelName
 * @returns {string}
 */
export function toSnake(contract, camelName) {
  return contract.fieldMapping.camelToSnake[camelName] || camelName;
}

/**
 * Get the TypeScript type for a contract field.
 *
 * @param {object} field — Contract field definition
 * @returns {string} TypeScript type string
 */
export function tsType(field) {
  const t = (field.type || "").toUpperCase();
  if (t.includes("INT") || t.includes("SERIAL") || t.includes("BIGINT") || t.includes("DECIMAL") || t.includes("NUMERIC") || t.includes("FLOAT") || t.includes("DOUBLE") || t.includes("REAL")) return "number";
  if (t.includes("BOOL")) return "boolean";
  if (t.includes("JSONB") || t.includes("JSON")) return "Record<string, unknown>";
  return "string";
}

/**
 * Get the SQLite column type for a contract field.
 *
 * @param {object} field — Contract field definition
 * @returns {string} SQLite type
 */
export function sqliteType(field) {
  const t = (field.type || "").toUpperCase();
  if (t.includes("UUID") || t.includes("TEXT") || t.includes("VARCHAR") || t.includes("CHAR")) return "TEXT";
  if (t.includes("INT") || t.includes("SERIAL") || t.includes("BIGINT")) return "INTEGER";
  if (t.includes("DECIMAL") || t.includes("NUMERIC") || t.includes("FLOAT") || t.includes("DOUBLE") || t.includes("REAL")) return "REAL";
  if (t.includes("BOOL")) return "INTEGER";
  if (t.includes("DATE") || t.includes("TIME") || t.includes("TIMESTAMP")) return "TEXT";
  if (t.includes("JSONB") || t.includes("JSON")) return "TEXT";
  return "TEXT";
}

/**
 * Get the non-auto fields for CreateInput (exclude id, created_at, updated_at).
 *
 * @param {object} entity — Contract entity
 * @returns {object[]} Fields for CreateInput
 */
export function createInputFields(entity) {
  return entity.fields.filter(f =>
    !f.isPrimary && !f.isAuto && f.name !== "created_at" && f.name !== "updated_at"
  );
}

/**
 * Get the non-identity fields for UpdateInput (exclude id, created_at, updated_at).
 *
 * @param {object} entity — Contract entity
 * @returns {object[]} Fields for UpdateInput
 */
export function updateInputFields(entity) {
  return createInputFields(entity);
}

/**
 * Check if an entity has the given field (by snake_case name).
 */
export function hasField(entity, snakeName) {
  return entity.fields.some(f => f.name === snakeName);
}

// ═══════════════════════════════════════════════════════
// 8. Export DOMAIN_ENTITIES for introspection
// ═══════════════════════════════════════════════════════

export { DOMAIN_ENTITIES };
