import { CONTRACT_CONSTANTS, CONTRACT_INTERFACES } from '../../'

const validatePricingInfo = (
	ideaComplete: CONTRACT_INTERFACES.ITradeIdea,
): string | undefined => {
	const idea = ideaComplete.idea as CONTRACT_INTERFACES.ITradeIdeaIdea
	if (idea.priceInfo === undefined) {
		return 'The idea must have priceInfo.'
	}
	const priceInfo = idea.priceInfo!
	if (!Array.isArray(priceInfo.response)) {
		return 'The idea must have priceInfo response as array.'
	}
	for (const resp of priceInfo.response) {
		if (typeof resp !== 'string') {
			return 'The idea must have priceInfo response as array of strings.'
		}
	}
	if (priceInfo.keys === undefined) {
		return 'The idea must have priceInfo keys.'
	}
	if (!Array.isArray(priceInfo.keys)) {
		return 'The idea must have priceInfo keys as array.'
	}
	for (const key of priceInfo.keys) {
		if (!Array.isArray(key)) {
			return 'The idea must have priceInfo keys as array of arrays.'
		}
		if (key.length !== 2) {
			return 'The idea must have priceInfo keys as array of arrays of length 2.'
		}
		for (const k of key) {
			if (typeof k !== 'string') {
				return 'The idea must have priceInfo keys as array of arrays of strings.'
			}
		}
	}
	if (priceInfo.price === undefined) {
		return 'The idea must have priceInfo price.'
	}
	if (priceInfo.price.provider === undefined) {
		return 'The idea must have priceInfo price provider.'
	}
	if (
		CONTRACT_CONSTANTS.PRICING_PROVIDER.find(
			(one) => one === priceInfo.price!.provider,
		) === undefined
	) {
		return 'The idea must have valid priceInfo price provider.'
	}
	if (priceInfo.price.symbol === undefined) {
		return 'The idea must have priceInfo price symbol.'
	}
	if (typeof priceInfo.price.symbol !== 'string') {
		return 'The idea must have priceInfo price symbol as string.'
	}
	if (priceInfo.price.timestamp === undefined) {
		return 'The idea must have priceInfo price timestamp.'
	}
	if (typeof priceInfo.price.timestamp !== 'number') {
		return 'The idea must have priceInfo price timestamp as number.'
	}
	if (
		priceInfo.price.ask === undefined &&
		priceInfo.price.bid !== undefined
	) {
		return 'The idea must have priceInfo price ask if it has bid.'
	}
	if (
		priceInfo.price.ask !== undefined &&
		priceInfo.price.bid === undefined
	) {
		return 'The idea must have priceInfo price bid if it has ask.'
	}
	if (priceInfo.price.globalPrice === undefined) {
		return 'The idea must have priceInfo price globalPrice.'
	}
	if (typeof priceInfo.price.globalPrice !== 'number') {
		return 'The idea must have priceInfo price globalPrice as number.'
	}
	if (priceInfo.price.globalPrice <= 0) {
		return 'The idea must have priceInfo price globalPrice greater than 0.'
	}
	return undefined
}

const validateBasicIdeaTrade = (
	ideaComplete: CONTRACT_INTERFACES.ITradeIdea,
): string | undefined => {
	const idea = ideaComplete.idea as CONTRACT_INTERFACES.ITradeIdeaIdea
	const strategyType = ideaComplete.strategy.ordersType!
	if (idea.kind === undefined) {
		return 'The idea must have kind.'
	}
	if (idea.kind === 'open') {
		if (idea.adjustment !== undefined) {
			return 'The idea must not have adjustment.'
		}
		if (idea.trade === undefined) {
			return 'The idea must have trade.'
		}
		if (strategyType === 'ALLOCATION') {
			if (idea.trade.allocation === undefined) {
				return 'The idea must have trade allocation.'
			}
			if (typeof idea.trade.allocation !== 'number') {
				return 'The idea must have trade allocation as number.'
			}
			if (idea.trade.allocation <= 0) {
				return 'The idea must have trade allocation greater than 0.'
			}
			if (idea.trade.allocation > 100) {
				return 'The idea must have trade allocation less or equal to 100.'
			}
		} else {
			if (idea.trade.conviction === undefined) {
				return 'The idea must have trade conviction.'
			}
			if (typeof idea.trade.conviction !== 'number') {
				return 'The idea must have trade conviction as number.'
			}
			if (idea.trade.conviction <= 0) {
				return 'The idea must have trade conviction greater than 0.'
			}
			if (idea.trade.conviction > 100) {
				return 'The idea must have trade conviction less or equal to 100.'
			}
		}
	} else if (idea.kind === 'adjust') {
		if (idea.adjustment === undefined) {
			return 'The idea must have adjustment object'
		}
		if (idea.adjustment!.kind === 'decrease') {
			if (idea.adjustment.percentage <= 0) {
				return 'The middle stages of the chained idea must have positive decrease.'
			} else if (idea.adjustment.percentage >= 100) {
				return 'The middle stages of the chained idea must have decrease less than 100.'
			}
		} else if (idea.adjustment!.kind === 'increase') {
			if (strategyType === 'ALLOCATION') {
				if (idea.adjustment.percentage < 0) {
					return 'The adjustment idea must have positive increase or zero for allocation.'
				}
			} else {
				if (idea.adjustment.percentage <= 0) {
					return 'The adjustment idea must have positive increase.'
				}
			}
		} else {
			return 'The idea must have adjustment kind as increase or decrease.'
		}
	} else if (idea.kind === 'close') {
		if (idea.adjustment !== undefined) {
			return 'The idea must not have adjustment.'
		}
		if (idea.trade !== undefined) {
			if (strategyType === 'ALLOCATION') {
				if (idea.trade.allocation === undefined) {
					return 'The idea must have trade allocation.'
				}
				if (typeof idea.trade.allocation !== 'number') {
					return 'The idea must have trade allocation as number.'
				}
				if (idea.trade.allocation !== 0) {
					return 'The idea must have trade allocation 0 when closing.'
				}
			} else {
				if (idea.trade.conviction === undefined) {
					return 'The idea must have trade conviction.'
				}
				if (typeof idea.trade.conviction !== 'number') {
					return 'The idea must have trade conviction as number.'
				}
				if (idea.trade.conviction <= 0) {
					return 'The idea must have trade conviction greater than 0.'
				}
				if (idea.trade.conviction > 100) {
					return 'The idea must have trade conviction less or equal to 100.'
				}
			}
		}
	} else {
		return 'The idea must have kind as open, close or adjust.'
	}
	if (idea.asset === undefined) {
		return 'The idea must have asset.'
	}
	if (idea.asset.ticker === undefined) {
		return 'The idea must have asset ticker.'
	}
	if (typeof idea.asset.ticker !== 'string') {
		return 'The idea must have asset ticker as string.'
	}
	if (idea.asset.ticker.trim().length === 0) {
		return 'The idea must have asset ticker as non empty string.'
	}
	if (idea.asset.description === undefined) {
		return 'The idea must have asset description.'
	}
	if (typeof idea.asset.description !== 'string') {
		return 'The idea must have asset description as string.'
	}
	if (idea.asset.description.trim().length === 0) {
		return 'The idea must have asset description as non empty string.'
	}
	if (idea.notes === undefined) {
		return 'The idea must have notes.'
	}
	if (idea.notes.commentary === undefined) {
		return 'The idea must have notes commentary.'
	}
	if (typeof idea.notes.commentary !== 'string') {
		return 'The idea must have notes commentary as string.'
	}
	if (idea.notes.commentary.trim().length === 0) {
		return 'The idea must have notes commentary as non empty string.'
	}
}

const validateBasicIdeaRoot = (
	ideaComplete: CONTRACT_INTERFACES.ITradeIdea,
	preMint: boolean = false,
): string | undefined => {
	if (!preMint) {
		if (ideaComplete.nftId === undefined) {
			return 'The idea must have nftId.'
		}
		if (typeof ideaComplete.nftId !== 'number') {
			return 'The idea must have nftId as number.'
		}
		if (ideaComplete.nftId <= 0) {
			return 'The idea must have nftId greater than 0.'
		}
	}
	if (ideaComplete.ideaSha512Hash === undefined) {
		return 'The idea must have ideaSha512Hash'
	}
	if (typeof ideaComplete.ideaSha512Hash !== 'string') {
		return 'The idea must have ideaSha512Hash as string'
	}
	if (ideaComplete.ideaSha512Hash.trim().length === 0) {
		return 'The idea must have ideaSha512Hash as non empty string'
	}
	if (ideaComplete.pricing === undefined) {
		return 'The idea must have pricing'
	}
	if (typeof ideaComplete.pricing.provider !== 'string') {
		return 'The idea must have pricing provider as string'
	}
	if (
		CONTRACT_CONSTANTS.PRICING_PROVIDER.find(
			(one) => one === ideaComplete.pricing.provider,
		) === undefined
	) {
		return 'The idea must have valid pricing provider'
	}
}

const validateBasicIdeaContent = (
	ideaComplete: CONTRACT_INTERFACES.ITradeIdea,
	preMint: boolean = false,
): string | undefined => {
	const idea = ideaComplete.idea as CONTRACT_INTERFACES.ITradeIdeaIdea
	if (ideaComplete.content === undefined) {
		return 'The idea must have content'
	}
	if (ideaComplete.content.reference === undefined) {
		return 'The idea must have content reference'
	}
	if (typeof ideaComplete.content.reference !== 'string') {
		return 'The idea must have content reference as string'
	}
	if (ideaComplete.content.reference.trim().length === 0) {
		return 'The idea must have content reference as non empty string'
	}
	if (!preMint) {
		if (ideaComplete.content.ideaNftId === undefined) {
			return 'The idea must have content ideaNftId'
		}
		if (ideaComplete.content.ideaNftId !== ideaComplete.nftId) {
			return 'The idea must have content ideaNftId equal to nftId'
		}
		if (ideaComplete.content.ideaStageKey === undefined) {
			return 'The idea must have content ideaStageKey'
		}
		if (typeof ideaComplete.content.ideaStageKey !== 'number') {
			return 'The idea must have content ideaStageKey as number'
		}
		if (ideaComplete.content.ideaStageKey < 0) {
			return 'The idea must have content ideaStageKey greater or equal 0'
		}
	}
	if (!preMint || idea.kind !== 'open') {
		if (ideaComplete.content.ideaKey === undefined) {
			return 'The idea must have content ideaKey'
		}
		if (typeof ideaComplete.content.ideaKey !== 'number') {
			return 'The idea must have content ideaKey as number'
		}
	}
}

const validateBasicEncryptedIdeaContent = (
	ideaComplete: CONTRACT_INTERFACES.ITradeIdea,
	preMint: boolean = false,
): string | undefined => {
	if (ideaComplete.content === undefined) {
		return 'The idea must have content'
	}
	if (ideaComplete.content.reference === undefined) {
		return 'The idea must have content reference'
	}
	if (typeof ideaComplete.content.reference !== 'string') {
		return 'The idea must have content reference as string'
	}
	if (ideaComplete.content.reference.trim().length === 0) {
		return 'The idea must have content reference as non empty string'
	}
	if (!preMint) {
		if (ideaComplete.content.ideaNftId === undefined) {
			return 'The idea must have content ideaNftId'
		}
		if (ideaComplete.content.ideaNftId !== ideaComplete.nftId) {
			return 'The idea must have content ideaNftId equal to nftId'
		}
		if (ideaComplete.content.ideaStageKey === undefined) {
			return 'The idea must have content ideaStageKey'
		}
		if (typeof ideaComplete.content.ideaStageKey !== 'number') {
			return 'The idea must have content ideaStageKey as number'
		}
		if (ideaComplete.content.ideaStageKey < 0) {
			return 'The idea must have content ideaStageKey greater or equal 0'
		}
	}
	if (!preMint) {
		if (ideaComplete.content.ideaKey === undefined) {
			return 'The idea must have content ideaKey'
		}
		if (typeof ideaComplete.content.ideaKey !== 'number') {
			return 'The idea must have content ideaKey as number'
		}
	}
}

const validateBasicIdeaCreator = (
	ideaComplete: CONTRACT_INTERFACES.ITradeIdea,
): string | undefined => {
	if (ideaComplete.creator === undefined) {
		return 'The idea must have creator'
	}
	if (ideaComplete.creator.name === undefined) {
		return 'The idea must have creator name'
	}
	if (typeof ideaComplete.creator.name !== 'string') {
		return 'The idea must have creator name as string'
	}
	if (ideaComplete.creator.name.trim().length === 0) {
		return 'The idea must have creator name as non empty string'
	}
	if (ideaComplete.creator.company !== undefined) {
		if (typeof ideaComplete.creator.company !== 'string') {
			return 'The idea must have creator company as string'
		}
		if (ideaComplete.creator.company.trim().length === 0) {
			return 'The idea must have creator company as non empty string'
		}
	}
	if (ideaComplete.creator.url !== undefined) {
		if (typeof ideaComplete.creator.url !== 'string') {
			return 'The idea must have creator url as string'
		}
		if (ideaComplete.creator.url.trim().length === 0) {
			return 'The idea must have creator url as non empty string'
		}
	}
	if (ideaComplete.creator.companyLogo?.cid !== undefined) {
		if (typeof ideaComplete.creator.companyLogo.cid !== 'string') {
			return 'The idea must have creator companyLogo as string'
		}
	}
	// if (ideaComplete.creator.backgroundImage !== undefined) {
	// 	if (typeof ideaComplete.creator.backgroundImage !== 'string') {
	// 		return 'The idea must have creator backgroundImage as string'
	// 	}
	// }
	if (ideaComplete.creator.walletAddress === undefined) {
		return 'The idea must have creator walletAddress'
	}
	if (typeof ideaComplete.creator.walletAddress !== 'string') {
		return 'The idea must have creator walletAddress as string'
	}
	if (ideaComplete.creator.walletAddress.trim().length === 0) {
		return 'The idea must have creator walletAddress as non empty string'
	}
	return undefined
}

const validateBasicIdeaStrategy = (
	ideaComplete: CONTRACT_INTERFACES.ITradeIdea,
	cachedStrategyState: CONTRACT_INTERFACES.IStrategyState,
	preMint: boolean = false,
): string | undefined => {
	if (ideaComplete.strategy === undefined) {
		return 'The idea must have strategy'
	}
	if (ideaComplete.strategy.reference === undefined) {
		return 'The idea must have strategy reference'
	}
	if (ideaComplete.strategy.uniqueKey === undefined) {
		return 'The idea must have strategy uniqueKey'
	}
	if (typeof ideaComplete.strategy.reference !== 'string') {
		return 'The idea must have strategy reference as string'
	}
	if (typeof ideaComplete.strategy.uniqueKey !== 'string') {
		return 'The idea must have strategy uniqueKey as string'
	}
	if (ideaComplete.strategy.reference.trim().length === 0) {
		return 'The idea must have strategy reference as non empty string'
	}
	if (ideaComplete.strategy.name === undefined) {
		return 'The idea must have strategy name'
	}
	if (typeof ideaComplete.strategy.name !== 'string') {
		return 'The idea must have strategy name as string'
	}
	if (ideaComplete.strategy.name.trim().length === 0) {
		return 'The idea must have strategy name as non empty string'
	}
	if (ideaComplete.strategy.description === undefined) {
		return 'The idea must have strategy description'
	}
	if (typeof ideaComplete.strategy.description !== 'string') {
		return 'The idea must have strategy description as string'
	}
	if (ideaComplete.strategy.description.trim().length === 0) {
		return 'The idea must have strategy description as non empty string'
	}
	if (preMint) {
		if (ideaComplete.strategy.createdAt === undefined) {
			ideaComplete.strategy.createdAt =
				cachedStrategyState.strategy.createdAt!
		}
		if (ideaComplete.strategy.changedAt === undefined) {
			ideaComplete.strategy.changedAt =
				cachedStrategyState.strategy.changedAt!
		}
	} else {
		if (ideaComplete.strategy.createdAt === undefined) {
			return 'The idea must have strategy createdAt'
		}
		if (typeof ideaComplete.strategy.createdAt !== 'number') {
			return 'The idea must have strategy createdAt as number'
		}
		if (ideaComplete.strategy.changedAt === undefined) {
			return 'The idea must have strategy changedAt'
		}
		if (typeof ideaComplete.strategy.changedAt !== 'number') {
			return 'The idea must have strategy changedAt as number'
		}
		if (ideaComplete.strategy.image?.cid !== undefined) {
			if (typeof ideaComplete.strategy.image.cid !== 'string') {
				return 'The idea must have strategy image as string'
			}
		}
	}
	if (ideaComplete.strategy.externalLink !== undefined) {
		if (typeof ideaComplete.strategy.externalLink !== 'string') {
			return 'The idea must have strategy externalLink as string'
		}
	}
	if (ideaComplete.strategy.ordersType === undefined) {
		if (preMint) {
			ideaComplete.strategy.ordersType =
				cachedStrategyState.strategy.ordersType!
		} else {
			return 'The idea must have strategy ordersType'
		}
	}
	if (typeof ideaComplete.strategy.ordersType !== 'string') {
		return 'The idea must have strategy ordersType as string'
	}
	if (
		ideaComplete.strategy.ordersType !== 'ALLOCATION' &&
		ideaComplete.strategy.ordersType !== 'STANDARD'
	) {
		return 'The idea must have strategy ordersType as ALLOCATION or STANDARD'
	}
	if (cachedStrategyState.strategy.ordersType !== undefined) {
		if (
			ideaComplete.strategy.ordersType !==
			cachedStrategyState.strategy.ordersType
		) {
			return (
				'The idea must have strategy ordersType equal to cached strategy ordersType ' +
				cachedStrategyState.strategy.ordersType +
				'.'
			)
		}
	}
}

export const validateBasicIdea = (
	ideaComplete: CONTRACT_INTERFACES.ITradeIdea,
	cachedStrategyState: CONTRACT_INTERFACES.IStrategyState,
	preMint: boolean = false,
): string | undefined => {
	let violation: string | undefined = undefined
	// nftId
	// ideaShar512Hash
	// pricing
	violation = validateBasicIdeaRoot(ideaComplete, preMint)
	if (violation !== undefined) {
		return violation
	}
	violation = validateBasicIdeaContent(ideaComplete, preMint)
	if (violation !== undefined) {
		return violation
	}
	violation = validateBasicIdeaStrategy(
		ideaComplete,
		cachedStrategyState,
		preMint,
	)
	if (violation !== undefined) {
		return violation
	}
	violation = validateBasicIdeaCreator(ideaComplete)
	if (violation !== undefined) {
		return violation
	}
	violation = validateBasicIdeaTrade(ideaComplete)
	if (violation !== undefined) {
		return violation
	}
	violation = validatePricingInfo(ideaComplete)
	if (violation !== undefined) {
		return violation
	}

	return undefined
}

export const validateBasicEncryptedIdea = (
	ideaComplete: CONTRACT_INTERFACES.ITradeIdea,
	cachedStrategyState: CONTRACT_INTERFACES.IStrategyState,
	preMint: boolean = false,
): string | undefined => {
	let violation: string | undefined = undefined
	// nftId
	// ideaShar512Hash
	// pricing
	violation = validateBasicIdeaRoot(ideaComplete, preMint)
	if (violation !== undefined) {
		return violation
	}
	violation = validateBasicEncryptedIdeaContent(ideaComplete, preMint)
	if (violation !== undefined) {
		return violation
	}
	violation = validateBasicIdeaStrategy(
		ideaComplete,
		cachedStrategyState,
		preMint,
	)
	if (violation !== undefined) {
		return violation
	}
	violation = validateBasicIdeaCreator(ideaComplete)
	if (violation !== undefined) {
		return violation
	}
	return undefined
}
