import { Request, Response, NextFunction } from 'express';
import { GetTokenByIdUseCase } from '../../application/use-cases/token/get-token-by-id.use-case';
import { GetTokensByNetworkUseCase } from '../../application/use-cases/token/get-tokens-by-network.use-case';
import { GetAllTokensUseCase } from '../../application/use-cases/token/get-all-tokens.use-case';
import { GetTokenChartUseCase } from '../../application/use-cases/token/get-token-chart.use-case';
import { GetTokenPricesUseCase } from '../../application/use-cases/token/get-token-prices.use-case';
import { GetTokenBySymbolUseCase } from '../../application/use-cases/token/get-token-by-symbol.use-case';
import { ResolveTokenByContractUseCase } from '../../application/use-cases/token/resolve-token-by-contract.use-case';
import { PaginationInput, TokenLookupInput, TokenPricesQueryInput } from '../../application/dto';

export class TokenController {
  constructor(
    private readonly getTokenByIdUseCase: GetTokenByIdUseCase,
    private readonly getTokenBySymbolUseCase: GetTokenBySymbolUseCase,
    private readonly getTokensByNetworkUseCase: GetTokensByNetworkUseCase,
    private readonly getAllTokensUseCase: GetAllTokensUseCase,
    private readonly getTokenChartUseCase: GetTokenChartUseCase,
    private readonly getTokenPricesUseCase: GetTokenPricesUseCase,
    private readonly resolveTokenByContractUseCase: ResolveTokenByContractUseCase,
  ) {}

  getById = async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const token = await this.getTokenByIdUseCase.execute(req.params.id as string);
      res.status(200).json({ success: true, data: token });
    } catch (error) {
      next(error);
    }
  };

  getBySymbol = async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const token = await this.getTokenBySymbolUseCase.execute(req.params.symbol as string);
      res.status(200).json({ success: true, data: token });
    } catch (error) {
      next(error);
    }
  };

  getByNetwork = async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tokens = await this.getTokensByNetworkUseCase.execute(
        req.params.networkId as string,
      );
      res.status(200).json({ success: true, data: tokens });
    } catch (error) {
      next(error);
    }
  };

  getAll = async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tokens = await this.getAllTokensUseCase.execute(
        req.query as unknown as PaginationInput,
      );
      res.status(200).json({ success: true, data: tokens });
    } catch (error) {
      next(error);
    }
  };

  getChart = async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const points = await this.getTokenChartUseCase.execute({
        tokenId: req.params.id as string,
        timeframe: (req.query.timeframe as string) ?? '1D',
      });
      res.status(200).json({ success: true, data: points });
    } catch (error) {
      next(error);
    }
  };

  getPrices = async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const input = req.query as unknown as TokenPricesQueryInput;
      const symbols = input.symbols.split(',').map(s => s.trim()).filter(Boolean);
      const prices = await this.getTokenPricesUseCase.execute(symbols);
      res.status(200).json({ success: true, data: prices });
    } catch (error) {
      next(error);
    }
  };

  lookupByContract = async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const result = await this.resolveTokenByContractUseCase.execute(
        req.body as TokenLookupInput,
      );
      res.status(200).json({ success: true, data: result });
    } catch (error) {
      next(error);
    }
  };
}
