import {
  Injectable,
  ConflictException,
  NotFoundException,
  BadRequestException,
} from '@nestjs/common';
import { ExchangeRateRepository } from './repositories/exchange-rate.repository';
import { CreateExchangeRateDto, UpdateExchangeRateDto } from './dto';
import { serviceMessages } from '../../common/constants/messages';

const MSG = serviceMessages('Exchange rate');

@Injectable()
export class ExchangeRateService {
  constructor(private readonly repo: ExchangeRateRepository) {}

  async findAll(query?: { page?: number; limit?: number; search?: string }) {
    return this.repo.findPaginatedWithSearch(query || {});
  }

  async findById(id: string) {
    const item = await this.repo.findById(id);
    if (!item) throw new NotFoundException(MSG.NOT_FOUND);
    return item;
  }

  async create(dto: CreateExchangeRateDto) {
    if (dto.from_currency_id === dto.to_currency_id) {
      throw new BadRequestException('From and To currencies must be different');
    }

    const existing = await this.repo.findByPair(dto.from_currency_id, dto.to_currency_id);
    if (existing) throw new ConflictException(MSG.ALREADY_EXISTS('currency pair'));

    const item = await this.repo.save({
      from_currency_id: dto.from_currency_id,
      to_currency_id: dto.to_currency_id,
      rate: dto.rate,
      effective_date: dto.effective_date,
      is_active: dto.is_active ?? true,
    });

    return { id: item.id, message: MSG.CREATED };
  }

  async update(id: string, dto: UpdateExchangeRateDto) {
    const item = await this.repo.findById(id);
    if (!item) throw new NotFoundException(MSG.NOT_FOUND);

    if (dto.from_currency_id && dto.to_currency_id && dto.from_currency_id === dto.to_currency_id) {
      throw new BadRequestException('From and To currencies must be different');
    }

    const fromId = dto.from_currency_id || item.from_currency_id;
    const toId = dto.to_currency_id || item.to_currency_id;
    if (fromId !== item.from_currency_id || toId !== item.to_currency_id) {
      const existing = await this.repo.findByPair(fromId, toId);
      if (existing && existing.id !== id) throw new ConflictException(MSG.ALREADY_EXISTS('currency pair'));
    }

    const updateData: any = {};
    for (const field of ['from_currency_id', 'to_currency_id', 'rate', 'effective_date', 'is_active']) {
      if ((dto as any)[field] !== undefined) updateData[field] = (dto as any)[field];
    }

    await this.repo.update(id, updateData);
    return { id, message: MSG.UPDATED };
  }

  async remove(id: string) {
    const item = await this.repo.findById(id);
    if (!item) throw new NotFoundException(MSG.NOT_FOUND);

    await this.repo.softDelete(id);
    return { message: MSG.DELETED };
  }
}
