{{TEMPLATE_IMPORTS}}
import { createAgent } from "@lucid-agents/core";
import { http } from "@lucid-agents/http";
import { wallets } from "@lucid-agents/wallet";
import { walletsFromEnv } from "@lucid-agents/wallet";
import { identity, identityFromEnv } from "@lucid-agents/identity";
import {
  createAgentIdentity,
  getTrustConfig,
  generateAgentRegistration,
  type AgentRegistrationOptions,
} from "@lucid-agents/identity";

{{TEMPLATE_PRE_SETUP}}
const selectedServices = [
  process.env.IDENTITY_INCLUDE_A2A === "true" ? "A2A" : undefined,
  process.env.IDENTITY_INCLUDE_WEB === "true" ? "web" : undefined,
  process.env.IDENTITY_INCLUDE_OASF === "true" ? "OASF" : undefined,
  process.env.IDENTITY_INCLUDE_TWITTER === "true" ? "twitter" : undefined,
  process.env.IDENTITY_INCLUDE_EMAIL === "true" ? "email" : undefined,
].filter(Boolean) as NonNullable<AgentRegistrationOptions["selectedServices"]>;

const parseRequiredJsonArray = (key: string, requireUri = false): string[] => {
  const raw = process.env[key];
  if (raw === undefined) {
    throw new Error(
      `[identity-template] Missing ${key}. Expected JSON array string (example: [])`
    );
  }

  let parsed: unknown;
  try {
    parsed = JSON.parse(raw);
  } catch {
    throw new Error(
      `[identity-template] Invalid ${key}. Expected JSON array string (example: [])`
    );
  }

  if (!Array.isArray(parsed)) {
    throw new Error(
      `[identity-template] Invalid ${key}. Expected JSON array string (example: [])`
    );
  }

  return parsed.map((value, index) => {
    if (typeof value !== "string" || !value.trim()) {
      throw new Error(
        `[identity-template] Invalid ${key}[${index}]. Expected non-empty string.`
      );
    }

    const normalized = value.trim();
    if (requireUri) {
      try {
        new URL(normalized);
      } catch {
        throw new Error(
          `[identity-template] Invalid ${key}[${index}]. Expected valid URI string.`
        );
      }
    }

    return normalized;
  });
};

const includeOASF = selectedServices.includes("OASF");
const oasfConfig = includeOASF
  ? {
      endpoint: process.env.IDENTITY_OASF_ENDPOINT,
      version: process.env.IDENTITY_OASF_VERSION,
      authors: parseRequiredJsonArray("IDENTITY_OASF_AUTHORS_JSON"),
      skills: parseRequiredJsonArray("IDENTITY_OASF_SKILLS_JSON"),
      domains: parseRequiredJsonArray("IDENTITY_OASF_DOMAINS_JSON"),
      modules: parseRequiredJsonArray("IDENTITY_OASF_MODULES_JSON", true),
      locators: parseRequiredJsonArray("IDENTITY_OASF_LOCATORS_JSON", true),
    }
  : undefined;

const registrationOptions: AgentRegistrationOptions = {
  name: process.env.AGENT_NAME,
  description: process.env.AGENT_DESCRIPTION,
  website: process.env.IDENTITY_WEBSITE,
  twitter: process.env.IDENTITY_TWITTER,
  email: process.env.IDENTITY_EMAIL,
  a2aEndpoint: process.env.IDENTITY_A2A_ENDPOINT,
  a2aVersion: process.env.IDENTITY_A2A_VERSION,
  oasf: oasfConfig,
  selectedServices: selectedServices.length > 0 ? selectedServices : undefined,
};

const agent = await createAgent({
  name: process.env.AGENT_NAME ?? "my-agent",
  version: process.env.AGENT_VERSION ?? "0.1.0",
  description: process.env.AGENT_DESCRIPTION,
})
  .use(http())
  .use(wallets({ config: walletsFromEnv() }))
  .use(identity({
    config: {
      ...identityFromEnv(),
      autoRegister: process.env.IDENTITY_AUTO_REGISTER === "true",
      registration: registrationOptions,
    }
  }))
  .build();

{{TEMPLATE_POST_SETUP}}
// Identity feature setup
// Note: The identity extension has already been configured above
// This section creates the on-chain identity using the agent's wallets
const identityResult = await createAgentIdentity({
  runtime: agent,
  domain: process.env.AGENT_DOMAIN,
  autoRegister: process.env.IDENTITY_AUTO_REGISTER === "true",
  rpcUrl: process.env.RPC_URL,
  chainId: process.env.CHAIN_ID ? parseInt(process.env.CHAIN_ID) : undefined,
  registration: registrationOptions,
});

if (identityResult.didRegister) {
  console.log("Registered agent on-chain!");
  console.log("Transaction:", identityResult.transactionHash);

  // IMPORTANT: After registration, you MUST host the ERC-8004 registration file at agentURI
  const registration = generateAgentRegistration(identityResult, registrationOptions);

  console.log("\nIMPORTANT: Host this registration file at:");
  console.log(`   https://${identityResult.domain}/.well-known/agent-registration.json\n`);
  console.log(JSON.stringify(registration, null, 2));
  console.log("\nWhy? The ERC-8004 registry stores this URL as the agentURI.");
  console.log("Anyone querying the registry will fetch this file to verify your agent's identity.");
  console.log("Without hosting this file, your agent's on-chain identity cannot be verified.\n");
} else if (identityResult.trust) {
  console.log("Found existing registration");
  console.log("Agent ID:", identityResult.record?.agentId);

  // Even if already registered, verify registration file is hosted
  if (identityResult.record?.agentURI) {
    console.log("Agent URI:", identityResult.record.agentURI);
    console.log("Ensure registration file is hosted at the agentURI location.");
  }
}

const trustConfig = getTrustConfig(identityResult);

// Example: Query validation summary (read operation)
// This demonstrates that the validation client is configured with the agent wallet
if (identityResult.clients?.validation && identityResult.record?.agentId) {
  console.log(
    "Fetching validation summary for agent ID:",
    identityResult.record.agentId.toString()
  );
  try {
    const summary = await identityResult.clients.validation.getSummary(
      identityResult.record.agentId
    );
    console.log("Validation summary:", {
      count: summary.count.toString(),
      averageResponse: summary.avgResponse,
    });
  } catch (error) {
    console.warn("Could not fetch validation summary:", error);
  }
} else {
  console.log("Validation client or agent ID not available:", {
    hasValidationClient: !!identityResult.clients?.validation,
    hasAgentId: !!identityResult.record?.agentId,
  });
}

// Example: Create validation request (write operation using agent wallet)
// This demonstrates write operations with the agent's private key
//
// IMPORTANT: The validatorAddress must be the address of a validator contract that will validate the request.
// This is typically a validator smart contract (e.g., stake-secured inference re-execution,
// zkML verifier, or TEE oracle). The validator will later respond with validationResponse.
//
// The agent (owner of agentId) calls this to request validation from a validator.
// The validator address should NOT be the agent's own address - it should be a separate validator.
//
// Note: This example uses a placeholder validator address for demonstration.
// In production, replace this with the actual validator contract address.
if (identityResult.clients?.validation && identityResult.record?.agentId) {
  try {
    const agentId = identityResult.record.agentId;

    // Placeholder validator address (replace with actual validator contract address in production)
    const validatorAddress =
      "0x0000000000000000000000000000000000000001" as const;

    // URI pointing to the validation request content (e.g., IPFS hash)
    const timestamp = Date.now();
    const requestUri = `https://${
      process.env.AGENT_DOMAIN || "agent.example.com"
    }/validation-request-${timestamp}.json`;

    console.log("Creating validation request...");
    console.log("Validator address:", validatorAddress);
    console.log("Agent ID:", agentId.toString());
    console.log("Request URI:", requestUri);

    // requestHash will be computed automatically from requestUri
    // Note: Function renamed: createRequest → validationRequest
    const txHash = await identityResult.clients.validation.validationRequest({
      validatorAddress,
      agentId,
      requestUri,
    });
    console.log("Created validation request! Transaction:", txHash);
    console.log(
      "Note: The validator at",
      validatorAddress,
      "should respond with validationResponse() (function renamed from submitResponse)"
    );
  } catch (error: any) {
    console.error("Could not create validation request:", error);
    if (error?.message) {
      console.error("Error message:", error.message);
    }
    if (error?.reason) {
      console.error("Error reason:", error.reason);
    }
  }
}

// Export identity feature clients
export const identityClient = identityResult.clients?.identity;
export const reputationClient = identityResult.clients?.reputation;
export const validationClient = identityResult.clients?.validation;
