import { z } from 'zod';
import { TransactionData } from '../../domain/value-objects/transaction-data';

const nativeTransferPathSchema = z.object({
  from: z.string().uuid(),
  to: z.string().uuid(),
  value: z.string(),
});

const tokenTransferPathSchema = z.object({
  from: z.string().uuid(),
  to: z.string().uuid(),
  fromTokenValue: z.string(),
  toTokenValue: z.string(),
});

const contractTokenTransferPathSchema = z.object({
  to: z.string().min(1),
  amount: z.string().min(1),
});

export const transactionDataSchema = z.array(
  z.union([
    nativeTransferPathSchema,
    tokenTransferPathSchema,
    contractTokenTransferPathSchema,
  ]),
) as z.ZodType<TransactionData[]>;

export const createTransactionSchema = z.object({
  hash: z.string().min(1),
  status: z.enum(['pending', 'confirmed', 'failed', 'dropped']),
  block: z.number().int().nullable().optional(),
  networkId: z.string().uuid(),
  timestamp: z.coerce.date(),
  from: z.string().min(1).nullable().optional(),
  to: z.string().min(1).nullable().optional(),
  interactedWith: z.string().uuid().nullable().optional(),
  value: z.string(),
  fee: z.string().nullable().optional(),
  gasPrice: z.string().nullable().optional(),
  gasLimit: z.number().int().nullable().optional(),
  method: z.string().min(1),
  data: transactionDataSchema.default([]),
});

export type CreateTransactionInput = z.infer<typeof createTransactionSchema>;

export const updateTransactionSchema = z.object({
  status: z.enum(['pending', 'confirmed', 'failed', 'dropped']).optional(),
  block: z.number().int().nullable().optional(),
});

export type UpdateTransactionInput = z.infer<typeof updateTransactionSchema>;

export const transactionIdParamSchema = z.object({
  id: z.string().uuid(),
});

export const getTransactionsQuerySchema = z.object({
  walletId: z.string().uuid().optional(),
  networkId: z.string().uuid().optional(),
  tokenId: z.string().uuid().optional(),
  status: z.enum(['pending', 'confirmed', 'failed', 'dropped']).optional(),
  method: z.string().optional(),
  limit: z.coerce.number().int().positive().max(100).default(20),
  offset: z.coerce.number().int().nonnegative().default(0),
});

export type GetTransactionsInput = z.infer<typeof getTransactionsQuerySchema>;

export const transactionRateSchema = z.object({
  networkId: z.string().uuid(),
  method: z.string().min(1),
  value: z.string().optional(),
  fee: z.string().nullable().optional(),
  gasPrice: z.string().nullable().optional(),
  gasLimit: z.number().int().nullable().optional(),
  data: transactionDataSchema.default([]).optional(),
  tokenIn: z.string().min(1).optional(),
  tokenOut: z.string().min(1).optional(),
  amountIn: z.string().optional(),
  amountOut: z.string().optional(),
});

export type TransactionRateInput = z.infer<typeof transactionRateSchema>;
