import { z } from 'zod';

const EthAddressSchema = z.string().regex(/^0x[a-fA-F0-9]{40}$/);

export const BasketAllocationSchema = z.object({
  symbol: z.string().min(2).max(16),
  targetWeightBps: z.number().int().positive().max(10_000),
  routeHint: z.string().optional(),
});

export type BasketAllocation = z.infer<typeof BasketAllocationSchema>;

export const BasketStatusSchema = z.enum(['draft', 'active', 'rebalancing', 'closed']);

export const BasketMandateSchema = z.object({
  id: z.string().uuid(),
  clientId: z.string().min(1),
  mandateName: z.string().min(1),
  chain138VaultAddress: EthAddressSchema,
  baseAssetSymbol: z.string().min(2).max(16).default('cBTC'),
  status: BasketStatusSchema,
  allocations: z.array(BasketAllocationSchema).min(1),
  createdAt: z.date().or(z.string().datetime()),
  updatedAt: z.date().or(z.string().datetime()),
});

export type BasketMandate = z.infer<typeof BasketMandateSchema>;

export const CreateBasketMandateSchema = BasketMandateSchema.omit({
  id: true,
  status: true,
  createdAt: true,
  updatedAt: true,
}).extend({
  baseAssetSymbol: z.string().min(2).max(16).default('cBTC'),
});

export type CreateBasketMandate = z.infer<typeof CreateBasketMandateSchema>;

export const BtcDepositStatusSchema = z.enum([
  'instruction_created',
  'pending_confirmations',
  'confirmed',
  'minted',
  'frozen',
]);

export const BtcDepositSchema = z.object({
  id: z.string().uuid(),
  clientId: z.string().min(1),
  basketId: z.string().uuid(),
  chain138VaultAddress: EthAddressSchema,
  depositAddress: z.string().min(16),
  expectedAmountSats: z.number().int().positive().optional(),
  confirmationsRequired: z.number().int().positive(),
  currentConfirmations: z.number().int().nonnegative(),
  status: BtcDepositStatusSchema,
  observedTxId: z.string().optional(),
  freezeReason: z.string().optional(),
  createdAt: z.date().or(z.string().datetime()),
  updatedAt: z.date().or(z.string().datetime()),
});

export type BtcDeposit = z.infer<typeof BtcDepositSchema>;

export const CreateBtcDepositSchema = z.object({
  clientId: z.string().min(1),
  basketId: z.string().uuid().optional(),
  mandateName: z.string().min(1).optional(),
  chain138VaultAddress: EthAddressSchema,
  allocations: z.array(BasketAllocationSchema).min(1).optional(),
  expectedAmountSats: z.number().int().positive().optional(),
  clientReference: z.string().min(1).optional(),
});

export type CreateBtcDeposit = z.infer<typeof CreateBtcDepositSchema>;

export const HoldingStatusSchema = z.enum(['pending_funding', 'funded']);

export const HoldingSchema = z.object({
  clientId: z.string().min(1),
  basketId: z.string().uuid(),
  symbol: z.string().min(2).max(16),
  allocationWeightBps: z.number().int().min(0).max(10_000),
  bookValueSats: z.number().int().nonnegative(),
  status: HoldingStatusSchema,
  updatedAt: z.date().or(z.string().datetime()),
});

export type Holding = z.infer<typeof HoldingSchema>;

export const RebalanceStatusSchema = z.enum(['planned', 'queued', 'executed', 'failed']);

export const RebalanceSchema = z.object({
  id: z.string().uuid(),
  clientId: z.string().min(1),
  basketId: z.string().uuid(),
  sourceSymbol: z.string().min(2).max(16),
  targetSymbols: z.array(z.string().min(2).max(16)).min(1),
  reason: z.string().min(1),
  status: RebalanceStatusSchema,
  createdAt: z.date().or(z.string().datetime()),
  updatedAt: z.date().or(z.string().datetime()),
});

export type Rebalance = z.infer<typeof RebalanceSchema>;

export const BridgeWithdrawalStatusSchema = z.enum(['pending', 'approved', 'submitted', 'failed']);

export const BridgeWithdrawalSchema = z.object({
  id: z.string().uuid(),
  clientId: z.string().min(1),
  basketId: z.string().uuid(),
  sourceSymbol: z.string().min(2).max(16),
  destinationSymbol: z.string().min(2).max(16),
  destinationChainId: z.number().int().positive(),
  destinationAddress: EthAddressSchema,
  amount: z.string().min(1),
  status: BridgeWithdrawalStatusSchema,
  createdAt: z.date().or(z.string().datetime()),
  updatedAt: z.date().or(z.string().datetime()),
});

export type BridgeWithdrawal = z.infer<typeof BridgeWithdrawalSchema>;

export const CreateBridgeWithdrawalSchema = BridgeWithdrawalSchema.omit({
  id: true,
  status: true,
  createdAt: true,
  updatedAt: true,
}).extend({
  sourceSymbol: z.string().min(2).max(16).optional(),
  destinationSymbol: z.string().min(2).max(16).optional(),
});

export type CreateBridgeWithdrawal = z.infer<typeof CreateBridgeWithdrawalSchema>;
