package com.ikon.projectmanagement.service.etl;

import java.time.LocalDate;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.springframework.stereotype.Component;

import com.ikon.connector.dto.response.FieldsConfigDto;
import com.ikon.connector.spi.ConnectorDataSync;
import com.ikon.projectmanagement.entity.ProductOfProject;
import com.ikon.projectmanagement.entity.Project;
import com.ikon.projectmanagement.repository.ProjectRepository;

import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component
@RequiredArgsConstructor
public class DealConnector implements ConnectorDataSync {

    private static final Logger log = LoggerFactory.getLogger(DealConnector.class);

    private final ProjectRepository projectRepository;

    @Override
    public List<FieldsConfigDto> getFieldsConfig() {
        List<FieldsConfigDto> fieldsConfig = new ArrayList<>();
        fieldsConfig
                .add(FieldsConfigDto.builder().key("dealIdentifier").label("Deal Identifier").type("string").build());
        fieldsConfig.add(FieldsConfigDto.builder().key("dealName").label("Deal Name").type("string").build());
        fieldsConfig.add(FieldsConfigDto.builder().key("projectName").label("Project Name").type("string").build());
        fieldsConfig.add(
                FieldsConfigDto.builder().key("accountIdentifier").label("Account Identifier").type("string").build());
        fieldsConfig.add(FieldsConfigDto.builder().key("dealStatus").label("Deal Status").type("string").build());
        fieldsConfig.add(FieldsConfigDto.builder().key("currency").label("Currency").type("string").build());
        fieldsConfig
                .add(FieldsConfigDto.builder().key("contractNumber").label("Contract Number").type("string").build());
        fieldsConfig.add(FieldsConfigDto.builder().key("contractedStartDate").label("Contracted Start Date")
                .type("string").build());
        fieldsConfig.add(
                FieldsConfigDto.builder().key("contractedEndDate").label("Contracted End Date").type("string").build());
        fieldsConfig.add(
                FieldsConfigDto.builder().key("parentProjectNo").label("Parent Project No").type("string").build());
        fieldsConfig
                .add(FieldsConfigDto.builder().key("isDebtRevenue").label("Is Debt Revenue").type("boolean").build());
        fieldsConfig
                .add(FieldsConfigDto.builder().key("leadIdentifier").label("Lead Identifier").type("string").build());
        fieldsConfig.add(FieldsConfigDto.builder().key("formattedActualRevenueIncludingVAT")
                .label("Formatted Actual Revenue Including VAT").type("string").build());
        fieldsConfig.add(FieldsConfigDto.builder().key("dealTeam").label("Deal Team").type("array").build());
        fieldsConfig.add(FieldsConfigDto.builder().key("updatedBy").label("Updated By").type("string").build());
        fieldsConfig
                .add(FieldsConfigDto.builder().key("dealStartDate").label("Deal Start Date").type("string").build());
        fieldsConfig
                .add(FieldsConfigDto.builder().key("productDetails").label("Product Details").type("object").build());
        return fieldsConfig;
    }

    @Override
    public String getModule() {
        return "Deal";
    }

    @Override
    @Transactional
    public void syncBatch(List<Map<String, Object>> payload) {

        log.info("[DealConnector] Received {} records for sync", payload.size());

        payload.stream()
                .filter(data -> {

                    String dealId = toStr(data.get("dealIdentifier"));
                    String status = toStr(data.get("dealStatus"));

                    log.info(
                            "[DealConnector] Evaluating deal [{}], status=[{}]",
                            dealId,
                            status);

                    return "WON".equalsIgnoreCase(status);
                })
                .forEach(data -> {

                    log.info("====================================================");
                    log.info("[DealConnector] Processing Deal");
                    log.info("====================================================");

                    log.info("[DealConnector] Full Payload : {}", data);

                    UUID dealIdentifier = parseUUID(data.get("dealIdentifier"));

                    UUID accountId = parseUUID(
                            data.get("accountIdentifier") != null
                                    ? data.get("accountIdentifier")
                                    : data.get("accountId"));

                    UUID leadIdentifier = parseUUID(data.get("leadIdentifier"));
                    UUID updatedByUUID = parseUUID(data.get("updatedBy"));

                    log.info(
                            "[DealConnector] dealIdentifier=[{}], accountId=[{}], leadIdentifier=[{}], updatedBy=[{}]",
                            dealIdentifier,
                            accountId,
                            leadIdentifier,
                            updatedByUUID);

                    Object rawProductDetails = data.get("productDetails");

                    log.info(
                            "[DealConnector] productDetails type=[{}]",
                            rawProductDetails != null
                                    ? rawProductDetails.getClass().getName()
                                    : "null");

                    log.info(
                            "[DealConnector] productDetails value=[{}]",
                            rawProductDetails);

                    ProductOfProject product = buildProduct(
                            rawProductDetails,
                            accountId,
                            dealIdentifier,
                            leadIdentifier);

                    if (product == null) {

                        log.warn(
                                "[DealConnector] Product creation FAILED for deal [{}]",
                                dealIdentifier);

                        log.warn(
                                "[DealConnector] Raw productDetails = {}",
                                rawProductDetails);

                        return;
                    }

                    log.info(
                            "[DealConnector] Product created successfully. productIdentifier=[{}], type=[{}]",
                            product.getProductIdentifier(),
                            product.getProductType());

                    String name = data.get("projectName") != null
                            ? (String) data.get("projectName")
                            : (String) data.get("dealName");

                    UUID projectManager = product.getProjectManager() != null
                            ? product.getProjectManager()
                            : accountId;

                    List<UUID> projectTeam = parseUUIDList(data.get("dealTeam"));

                    Project project = Project.builder()
                            .projectIdentifier(dealIdentifier)
                            .accountId(accountId)
                            .projectName(name)
                            .projectStatus((String) data.get("dealStatus"))
                            .currency((String) data.get("currency"))
                            .isDebtRevenue_deal((Boolean) data.get("isDebtRevenue"))
                            .formattedActualRevenueIncludingVAT_deal(
                                    toStr(data.get("formattedActualRevenueIncludingVAT_contracted")))
                            .contractNumber(toStr(data.get("contractNumber")))
                            .contractedStartDate(parseDate((String) data.get("contractedStartDate")))
                            .contractedEndDate(parseDate((String) data.get("contractedEndDate")))
                            .projectStartDate(parseDate((String) data.get("dealStartDate")))
                            .parentProjectNo((String) data.get("parentProjectNo"))
                            .projectManager(projectManager)
                            .updatedBy(updatedByUUID)
                            .projectTeam(projectTeam)
                            .source("SalesCRM")
                            .product(product)
                            .build();

                    log.info(
                            "[DealConnector] Saving project for deal [{}] projectName=[{}]",
                            dealIdentifier,
                            name);

                    projectRepository.save(project);

                    log.info(
                            "[DealConnector] Project saved successfully for deal [{}]",
                            dealIdentifier);
                });
    }

    private ProductOfProject buildProduct(
            Object raw,
            UUID accountId,
            UUID projectIdentifier,
            UUID leadIdentifier) {

        log.info(
                "[DealConnector] buildProduct() called. rawType=[{}]",
                raw != null ? raw.getClass().getName() : "null");

        if (raw == null) {

            log.warn(
                    "[DealConnector] productDetails is NULL for deal [{}]",
                    projectIdentifier);

            return null;
        }

        if (!(raw instanceof Map)) {

            log.warn(
                    "[DealConnector] productDetails is NOT a Map. type=[{}], value=[{}]",
                    raw.getClass().getName(),
                    raw);

            return null;
        }

        Map<?, ?> productMap = (Map<?, ?>) raw;

        log.info(
                "[DealConnector] productDetails contains {} entries",
                productMap.size());

        if (productMap.isEmpty()) {

            log.warn(
                    "[DealConnector] productDetails map is EMPTY");

            return null;
        }

        productMap.forEach((key, value) -> {

            log.info(
                    "[DealConnector] Entry key=[{}], valueType=[{}]",
                    key,
                    value != null ? value.getClass().getName() : "null");

            log.info(
                    "[DealConnector] Entry value=[{}]",
                    value);
        });

        for (Object value : productMap.values()) {

            if (!(value instanceof Map)) {

                log.warn(
                        "[DealConnector] Product entry is not Map : {}",
                        value);

                continue;
            }

            Map<?, ?> pd = (Map<?, ?>) value;

            String productType = toStr(pd.get("productType"));

            log.info(
                    "[DealConnector] Checking productType=[{}]",
                    productType);

            if (!"Professional Service".equalsIgnoreCase(productType)) {

                log.info(
                        "[DealConnector] Skipping product because type is [{}]",
                        productType);

                continue;
            }

            log.info(
                    "[DealConnector] Professional Service product FOUND");

            UUID pmUuid = tryParseUUID(toStr(pd.get("projectManager")));

            UUID productId = tryParseUUID(toStr(pd.get("productIdentifier")));

            log.info(
                    "[DealConnector] productIdentifier=[{}], projectManager=[{}]",
                    productId,
                    pmUuid);

            return ProductOfProject.builder()
                    .productIdentifier(productId)
                    .projectIdentifier(projectIdentifier)
                    .accountId(accountId)
                    .leadIdentifier(leadIdentifier)
                    .productType(productType)
                    .productDescription(
                            toStr(pd.get("productDescription")))
                    .discountPercent(
                            toDouble(pd.get("discountPercent")))
                    .projectManager(pmUuid)
                    .productStatus("Active")
                    .build();
        }

        log.warn(
                "[DealConnector] No Professional Service product found in productDetails. productMap={}",
                productMap);

        return null;
    }

    // ---------------------------------------------------------------------------
    // Helpers
    // ---------------------------------------------------------------------------
    private UUID parseUUID(Object value) {
        if (value == null)
            return null;
        try {
            return UUID.fromString(value.toString());
        } catch (Exception e) {
            return null;
        }
    }

    private UUID tryParseUUID(String value) {
        if (value == null)
            return null;
        try {
            return UUID.fromString(value);
        } catch (Exception e) {
            return null;
        }
    }

    private List<UUID> parseUUIDList(Object value) {
        List<UUID> result = new ArrayList<>();
        if (!(value instanceof List))
            return result;
        for (Object item : (List<?>) value) {
            UUID uuid = parseUUID(item);
            if (uuid != null)
                result.add(uuid);
        }
        return result;
    }

    private LocalDate parseDate(String value) {
        if (value == null || value.isBlank())
            return null;
        try {
            return LocalDate.parse(value);
        } catch (DateTimeParseException e) {
            return null;
        }
    }

    private String toStr(Object value) {
        return value != null ? String.valueOf(value) : null;
    }

    private Double toDouble(Object value) {
        if (value instanceof Number)
            return ((Number) value).doubleValue();
        return null;
    }
}