/**
 * Blockchain Server Actions
 *
 * Server-side functions for blockchain operations:
 * - Register a contract document on the blockchain
 * - Verify a contract's on-chain proof
 * - Get all blockchain transactions for the user
 * - Get blockchain network stats
 *
 * These actions are called from the frontend via React Server Actions.
 * All blockchain logic runs server-side (no MetaMask needed).
 */

"use server";

import { auth } from "@clerk/nextjs/server";
import { revalidatePath } from "next/cache";
import { prisma } from "@/lib/db/prisma";
import { BlockchainService } from "@/lib/services/blockchain.service";
import { NotificationService } from "@/lib/services/notification.service";
import { ContractService } from "@/lib/services/contract.service";
import { CertificateService } from "@/lib/services/certificate.service";
import type {
  BlockchainTransactionView,
  BlockchainStats,
  CryptographicCertificate,
} from "@/lib/services/blockchain.types";

/**
 * Register a contract's document on the blockchain.
 *
 * FLOW:
 * 1. Authenticate user
 * 2. Fetch contract from DB
 * 3. Download PDF and compute SHA-256 hash
 * 4. Send hash to the smart contract on-chain
 * 5. Store proof data (txHash, blockNumber, etc.) in PostgreSQL
 * 6. Create a BlockchainTransaction record for the explorer
 * 7. Create a notification for the user
 *
 * @param contractId - The contract ID to register
 */
export async function registerContractOnBlockchain(contractId: string) {
  try {
    const { userId: clerkId } = await auth();
    if (!clerkId) return { success: false, error: "Unauthorized" };

    // Check if blockchain is configured
    if (!BlockchainService.isConfigured()) {
      return {
        success: false,
        error:
          "Blockchain not configured. Start a Hardhat node and check your .env.",
      };
    }

    // Get internal user
    const user = await ContractService.getUserByClerkId(clerkId);
    if (!user) return { success: false, error: "User not found" };

    // Get the contract
    const contract = await ContractService.getById(contractId);
    if (contract.userId !== user.id) {
      return { success: false, error: "Unauthorized" };
    }

    // Check if already registered
    if (contract.txHash && contract.txHash !== "already-registered") {
      return {
        success: true,
        message: "Contract already registered on blockchain",
        proof: {
          documentHash: contract.documentHash,
          txHash: contract.txHash,
          blockNumber: contract.blockNumber,
        },
      };
    }

    // Hash the document and register on-chain
    const proof = await BlockchainService.hashAndRegister(
      contract.fileUrl,
      contract.fileName,
    );

    // Save proof data to the Contract record
    await prisma.contract.update({
      where: { id: contractId },
      data: {
        documentHash: proof.documentHash,
        txHash: proof.txHash,
        blockNumber: proof.blockNumber,
        blockTimestamp: proof.blockTimestamp,
        blockchainNetwork: proof.network,
        contractAddress: proof.contractAddress,
      },
    });

    // Create a BlockchainTransaction record for the explorer
    await prisma.blockchainTransaction.create({
      data: {
        userId: user.id,
        contractId,
        documentHash: proof.documentHash,
        txHash: proof.txHash,
        blockNumber: proof.blockNumber,
        blockTimestamp: proof.blockTimestamp,
        network: proof.network,
        contractAddress: proof.contractAddress,
        status: "CONFIRMED",
      },
    });

    // Create success notification
    await NotificationService.create({
      userId: user.id,
      type: "SUCCESS",
      title: "🔗 Blockchain Verified",
      message: `"${contract.title || contract.fileName}" has been registered on-chain. Tx: ${proof.txHash.slice(0, 16)}...`,
      contractId,
      actionType: "BLOCKCHAIN_REGISTERED",
      icon: "Link2",
      expiresIn: 14 * 24 * 60 * 60 * 1000, // 14 days
    });

    revalidatePath("/contacts");
    revalidatePath("/dashboard");
    revalidatePath("/blockchain");

    return {
      success: true,
      message: "Document registered on blockchain!",
      proof: {
        documentHash: proof.documentHash,
        txHash: proof.txHash,
        blockNumber: proof.blockNumber,
        blockTimestamp: proof.blockTimestamp.toISOString(),
        network: proof.network,
        explorerUrl: proof.explorerUrl,
      },
    };
  } catch (error: unknown) {
    console.error("❌ Blockchain registration error:", error);
    return {
      success: false,
      error:
        error instanceof Error ? error.message : "Unknown blockchain error",
    };
  }
}

/**
 * Verify a contract's on-chain proof by checking the blockchain directly.
 */
export async function verifyContractOnBlockchain(contractId: string) {
  try {
    const { userId: clerkId } = await auth();
    if (!clerkId) return { success: false, error: "Unauthorized" };

    if (!BlockchainService.isReadConfigured()) {
      return {
        success: false,
        error: "Blockchain not configured for verification",
      };
    }

    const user = await ContractService.getUserByClerkId(clerkId);
    if (!user) return { success: false, error: "User not found" };

    const contract = await ContractService.getById(contractId);
    if (contract.userId !== user.id)
      return { success: false, error: "Unauthorized" };

    if (!contract.documentHash) {
      return {
        success: true,
        verification: { exists: false, timestamp: 0, depositor: "" },
      };
    }

    const verification = await BlockchainService.verifyOnChain(
      contract.documentHash,
    );

    return {
      success: true,
      verification: {
        exists: verification.exists,
        timestamp: verification.timestamp,
        depositor: verification.depositor,
        documentHash: contract.documentHash,
        txHash: contract.txHash,
        blockNumber: contract.blockNumber,
        network: contract.blockchainNetwork,
      },
    };
  } catch (error: unknown) {
    console.error("❌ Blockchain verification error:", error);
    return {
      success: false,
      error: error instanceof Error ? error.message : "Unknown error",
    };
  }
}

/**
 * Verify a raw document hash on-chain (for the verification panel).
 */
export async function verifyDocumentHashOnBlockchain(documentHash: string) {
  try {
    const { userId: clerkId } = await auth();
    if (!clerkId) return { success: false, error: "Unauthorized" };

    if (!BlockchainService.isReadConfigured()) {
      return {
        success: false,
        error: "Blockchain not configured for verification",
      };
    }

    // Ensure proper format
    const rawHash = documentHash.trim();
    const hash = rawHash.startsWith("0x") ? rawHash : `0x${rawHash}`;

    if (!/^0x[a-fA-F0-9]{64}$/.test(hash)) {
      return {
        success: false,
        error: "Invalid hash format. Expected a 32-byte SHA-256 hex string.",
      };
    }

    const verification = await BlockchainService.verifyOnChain(hash);

    return {
      success: true,
      verification: {
        exists: verification.exists,
        timestamp: verification.timestamp,
        depositor: verification.depositor,
      },
    };
  } catch (error: unknown) {
    console.error("❌ Hash verification error:", error);
    return {
      success: false,
      error: error instanceof Error ? error.message : "Unknown error",
    };
  }
}

/**
 * Get all blockchain transactions for the authenticated user.
 * Used by the blockchain explorer page.
 */
export async function getBlockchainTransactions(): Promise<{
  success: boolean;
  transactions?: BlockchainTransactionView[];
  error?: string;
}> {
  try {
    const { userId: clerkId } = await auth();
    if (!clerkId) return { success: false, error: "Unauthorized" };

    const user = await ContractService.getUserByClerkId(clerkId);
    if (!user) return { success: false, error: "User not found" };

    const txs = await prisma.blockchainTransaction.findMany({
      where: { userId: user.id },
      orderBy: { createdAt: "desc" },
      include: {
        contract: {
          select: {
            id: true,
            title: true,
            fileName: true,
          },
        },
      },
    });

    const transactions: BlockchainTransactionView[] = txs.map((tx) => ({
      id: tx.id,
      contractId: tx.contractId,
      contractTitle: tx.contract.title,
      contractFileName: tx.contract.fileName,
      documentHash: tx.documentHash,
      txHash: tx.txHash,
      blockNumber: tx.blockNumber,
      blockTimestamp: tx.blockTimestamp.toISOString(),
      network: tx.network,
      contractAddress: tx.contractAddress,
      status: tx.status,
      createdAt: tx.createdAt.toISOString(),
      explorerUrl:
        tx.network === "sepolia"
          ? `https://sepolia.etherscan.io/tx/${tx.txHash}`
          : null,
    }));

    return { success: true, transactions };
  } catch (error: unknown) {
    console.error("❌ Get transactions error:", error);
    return {
      success: false,
      error: error instanceof Error ? error.message : "Unknown error",
    };
  }
}

/**
 * Get blockchain network stats for the explorer page header.
 */
export async function getBlockchainStats(): Promise<{
  success: boolean;
  stats?: BlockchainStats;
  error?: string;
}> {
  try {
    const { userId: clerkId } = await auth();
    if (!clerkId) return { success: false, error: "Unauthorized" };

    const stats = await BlockchainService.getNetworkStats();
    return { success: true, stats };
  } catch (error: unknown) {
    console.error("❌ Blockchain stats error:", error);
    return {
      success: false,
      error: error instanceof Error ? error.message : "Unknown error",
    };
  }
}

/**
 * Generate a cryptographic certificate for a blockchain-registered contract.
 *
 * The certificate contains:
 * - Contract metadata
 * - Blockchain proof (txHash, block, timestamp)
 * - A digital signature created by the server wallet
 *
 * @param contractId - The contract ID
 * @returns Certificate data (JSON) or error
 */
export async function generateContractCertificate(contractId: string): Promise<{
  success: boolean;
  certificate?: CryptographicCertificate;
  certificateJson?: string;
  certificatePdfBase64?: string;
  certificateFileName?: string;
  error?: string;
}> {
  try {
    const { userId: clerkId } = await auth();
    if (!clerkId) return { success: false, error: "Unauthorized" };

    if (!BlockchainService.isReadConfigured()) {
      return {
        success: false,
        error: "Blockchain not configured for certificate generation",
      };
    }

    const user = await ContractService.getUserByClerkId(clerkId);
    if (!user) return { success: false, error: "User not found" };

    const contract = await ContractService.getById(contractId);
    if (contract.userId !== user.id) {
      return {
        success: false,
        error: "Unauthorized: Contract does not belong to you",
      };
    }

    // Check if contract is registered on blockchain
    if (!contract.documentHash || !contract.txHash) {
      return {
        success: false,
        error:
          "Contract is not registered on blockchain. Register it first to generate a certificate.",
      };
    }

    // Generate the certificate
    const certificate = await CertificateService.generateCertificate(
      contract.id,
      contract.title,
      contract.fileName,
      contract.documentHash,
      contract.txHash,
      contract.blockNumber || 0,
      contract.blockTimestamp?.toISOString() || new Date().toISOString(),
      contract.blockchainNetwork || "hardhat",
      contract.contractAddress || "",
    );

    // Generate a professional PDF for download
    const pdfBuffer =
      await CertificateService.generateCertificatePdf(certificate);
    const certificatePdfBase64 = pdfBuffer.toString("base64");

    const baseName = (contract.title || contract.fileName || contract.id)
      .replace(/[^a-zA-Z0-9-_]+/g, "-")
      .replace(/^-+|-+$/g, "")
      .slice(0, 64);
    const dateStamp = new Date().toISOString().slice(0, 10);
    const certificateFileName = `certificate-${baseName || contract.id}-${dateStamp}.pdf`;

    // Keep JSON available for internal use or auditing if needed
    const certificateJson = JSON.stringify(certificate, null, 2);

    return {
      success: true,
      certificate,
      certificateJson,
      certificatePdfBase64,
      certificateFileName,
    };
  } catch (error: unknown) {
    console.error("❌ Certificate generation error:", error);
    return {
      success: false,
      error: error instanceof Error ? error.message : "Unknown error",
    };
  }
}
