package com.ikon.projectmanagement.service.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import com.ikon.projectmanagement.dto.response.FxRateDto;
import com.ikon.projectmanagement.entity.FxRateEntity;
import com.ikon.projectmanagement.entity.FxRateEntity;
import com.ikon.projectmanagement.repository.FxRateRepository;
import com.ikon.projectmanagement.service.ImportFxRateService;
import com.ikon.webservice.WebService;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Service
@RequiredArgsConstructor
@Slf4j
public class ImportFxRateServiceImpl extends WebService implements ImportFxRateService {

    private final RestTemplate restTemplate;
    private final FxRateRepository fxRateRepository;

    @Value("${salescrm.api.base-url}")
    private String salesCrmBaseUrl;

    private HttpHeaders createHeaders(String accessToken) {
        HttpHeaders headers = new HttpHeaders();
        if (accessToken != null && !accessToken.isEmpty()) {
            headers.set("Authorization", accessToken);
        }
        headers.set("Content-Type", "application/json");
        return headers;
    }

    private static final int PAGE_SIZE = 200;

    @Override
    @Transactional
    public List<FxRateDto> importFxRates(String accessToken) {
        String baseUrl = salesCrmBaseUrl + "/fxrate";
        log.info("Fetching all FX rates from Sales CRM: {}", baseUrl);
        try {
            HttpEntity<Void> entity = new HttpEntity<>(createHeaders(accessToken));
            List<SalesCrmFxRateDto> allRaw = new ArrayList<>();
            int page = 0;
            int totalPages = 1;

            while (page < totalPages) {
                String url = baseUrl + "?page=" + page + "&size=" + PAGE_SIZE;
                ResponseEntity<PageResponse<SalesCrmFxRateDto>> response = restTemplate.exchange(
                        url, HttpMethod.GET, entity,
                        new ParameterizedTypeReference<PageResponse<SalesCrmFxRateDto>>() {});

                if (response.getBody() == null || response.getBody().getContent() == null) {
                    break;
                }

                PageResponse<SalesCrmFxRateDto> body = response.getBody();
                allRaw.addAll(body.getContent());
                totalPages = body.getTotalPages();
                log.info("Fetched FX rates page {}/{}", page + 1, totalPages);
                page++;
            }

            List<FxRateDto> dtos = allRaw.stream()
                    .map(this::mapToFxRateDto)
                    .collect(Collectors.toList());

            List<FxRateEntity> entities = dtos.stream().map(dto -> FxRateEntity.builder()
                    .fxRateId(dto.getId())
                    .accountIdentifier(dto.getAccountId())
                    .build()).collect(Collectors.toList());

            if (!entities.isEmpty()) {
                fxRateRepository.saveAll(entities);
                log.info("Saved/Updated {} FX rates in total", entities.size());
            }

            return dtos;
        } catch (RestClientException e) {
            log.error("Failed to fetch FX rates from Sales CRM: {}", e.getMessage());
            return Collections.emptyList();
        }
    }

    private FxRateDto mapToFxRateDto(SalesCrmFxRateDto source) {
        BigDecimal rateValue = BigDecimal.ZERO;
        if (source.getRate() != null) {
            try {
                rateValue = new BigDecimal(source.getRate());
            } catch (NumberFormatException e) {
                log.warn("Invalid rate format for id {}: {}", source.getId(), source.getRate());
            }
        }
        return FxRateDto.builder()
                .id(source.getId())
                .accountId(source.getAccountId())
                .toCurrency(source.getCurrency())
                .fromCurrency("USD")
                .rate(rateValue)
                .effectiveDate(source.getYear())
                .build();
    }

    @Data
    public static class PageResponse<T> {
        private List<T> content;
        private int totalPages;
        private long totalElements;
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    private static class SalesCrmFxRateDto {
        private UUID id;
        private UUID accountId;
        private String year;
        private String rate;
        private String currency;
    }
}
