import { Request, Response, NextFunction } from 'express';
import { Wallet } from '../../domain/entities/wallet';
import { GenerateWalletSeedphraseUseCase } from '../../application/use-cases/wallet/generate-seedphrase.use-case';
import { CreateWalletUseCase } from '../../application/use-cases/wallet/create-wallet.use-case';
import { GetWalletByIdUseCase } from '../../application/use-cases/wallet/get-wallet-by-id.use-case';
import { GetWalletsByDeviceUseCase } from '../../application/use-cases/wallet/get-wallets-by-device.use-case';
import { GetWalletAddressForNetworkUseCase } from '../../application/use-cases/wallet/get-wallet-address-for-network.use-case';
import { GetAllNetworkAddressesForWalletUseCase } from '../../application/use-cases/wallet/get-all-network-addresses-for-wallet.use-case';
import { GetWalletSeedPhraseUseCase } from '../../application/use-cases/wallet/get-wallet-seed-phrase.use-case';
import {
  CreateWalletInput,
  SeedPhraseInput,
} from '../../application/dto';

const maskWallet = (wallet: Wallet) => {
  return {
    id: wallet.id,
    name: wallet.name,
    syncType: wallet.syncType,
    syncedAt: wallet.syncedAt,
    deviceIds: wallet.deviceIds,
    isAdmin: wallet.isAdmin,
    isActive: wallet.isActive,
    lastAccessedAt: wallet.lastAccessedAt,
    version: wallet.version,
    createdAt: wallet.createdAt,
    updatedAt: wallet.updatedAt,
  };
};

export class WalletController {
  constructor(
    private readonly generateSeedphraseUseCase: GenerateWalletSeedphraseUseCase,
    private readonly createWalletUseCase: CreateWalletUseCase,
    private readonly getWalletByIdUseCase: GetWalletByIdUseCase,
    private readonly getWalletsByDeviceUseCase: GetWalletsByDeviceUseCase,
    private readonly getWalletAddressForNetworkUseCase: GetWalletAddressForNetworkUseCase,
    private readonly getAllNetworkAddressesForWalletUseCase: GetAllNetworkAddressesForWalletUseCase,
    private readonly getWalletSeedPhraseUseCase: GetWalletSeedPhraseUseCase,
  ) {}

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

  create = async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const wallet = await this.createWalletUseCase.execute(req.body as CreateWalletInput);
      res.status(201).json({ success: true, data: maskWallet(wallet) });
    } catch (error) {
      next(error);
    }
  };

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

  getByDevice = async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const wallets = await this.getWalletsByDeviceUseCase.execute(
        req.params.deviceId as string,
      );
      res.status(200).json({ success: true, data: wallets.map(maskWallet) });
    } catch (error) {
      next(error);
    }
  };

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

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

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