package com.gxwebsoft.house.ai;

import cn.hutool.core.util.StrUtil;
import com.gxwebsoft.house.entity.HouseAiHouseCard;
import com.gxwebsoft.house.entity.HouseAiIntent;
import com.gxwebsoft.house.entity.HouseInfo;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * AI找房推荐解释器，负责回答话术和每套房源的匹配说明。
 */
@Component
public class HouseAiRecommendationExplainer {

    private static final Pattern NUMBER_PATTERN = Pattern.compile("(\\d+)");

    private static final Pattern HOUSE_TYPE_COMPARTMENT_PATTERN = Pattern.compile("([一二两三四五六七八九十0-9]{1,2})\\s*隔间");
    private static final Pattern HOUSE_TYPE_ROOM_HALL_PATTERN = Pattern.compile("([一二两三四五六七八九十0-9]{1,2})\\s*室\\s*([一二两三四五六七八九十0-9]{1,2})\\s*厅");

    public String buildHouseAnswer(HouseAiIntent intent, HouseAiSearchResult result, boolean hasFaqMatches) {
        if (hasFaqMatches && HouseAiMatchTypes.EXACT.equals(result.getMatchType())) {
            return "优先为您匹配到常见问题答案，同时按您的需求筛选到以下房源：";
        }
        if (HouseAiMatchTypes.APPROXIMATE.equals(result.getMatchType())) {
            return buildApproximateAnswer(intent, result.getHouses().size());
        }
        return buildExactAnswer(intent, result.getHouses().size());
    }

    public String buildNoCandidateAnswer(HouseAiIntent intent) {
        StringBuilder sb = new StringBuilder("暂时没有找到符合条件或接近条件的房源。");
        if (StrUtil.isNotBlank(intent.getRegionKeyword())) {
            sb.append("可以先放宽").append(intent.getRegionKeyword()).append("周边范围，");
        } else {
            sb.append("可以补充区域或商圈，");
        }
        sb.append("也可以调整面积、预算或留下联系方式，顾问会继续为您跟进。");
        return sb.toString();
    }

    public List<HouseAiHouseCard> toHouseCards(HouseAiSearchResult result, HouseAiIntent intent) {
        return result.getHouses().stream()
            .map(item -> toHouseCard(item, intent, result.getMatchType()))
            .collect(Collectors.toList());
    }

    private HouseAiHouseCard toHouseCard(HouseInfo item, HouseAiIntent intent, String matchType) {
        HouseAiHouseCard card = new HouseAiHouseCard();
        card.setHouseId(item.getHouseId());
        card.setHouseTitle(item.getHouseTitle());
        card.setHouseType(item.getHouseType());
        card.setExtent(item.getExtent());
        card.setFloor(item.getFloor());
        card.setToward(item.getToward());
        card.setMonthlyRent(item.getMonthlyRent() == null ? null : item.getMonthlyRent().stripTrailingZeros().toPlainString());
        card.setCity(item.getCity());
        card.setRegion(item.getRegion());
        card.setAddress(item.getAddress());
        card.setFiles(item.getFiles());
        card.setSupporting(item.getSupporting());
        card.setMatchReason(buildMatchReason(item, intent, matchType));
        return card;
    }

    private String buildApproximateAnswer(HouseAiIntent intent, int size) {
        StringBuilder sb = new StringBuilder("我按");
        List<String> desc = buildConditionDescriptions(intent);
        if (desc.isEmpty()) {
            sb.append("您的找房需求");
        } else {
            sb.append(String.join("、", desc));
        }
        sb.append("筛了一遍，暂时没有完全匹配的房源。先给您看");
        sb.append(size).append("套比较接近的，主要差异我也标在卡片里。");
        return sb.toString();
    }

    private String buildExactAnswer(HouseAiIntent intent, int size) {
        StringBuilder sb = new StringBuilder("已根据您的需求筛选到");
        sb.append(size).append("套较匹配的房源");
        List<String> desc = buildConditionDescriptions(intent);
        if (!desc.isEmpty()) {
            sb.append("，条件包括：").append(String.join("、", desc));
        }
        sb.append("。");
        return sb.toString();
    }

    private List<String> buildConditionDescriptions(HouseAiIntent intent) {
        List<String> desc = new ArrayList<>();
        if (intent.getExtentMin() != null && intent.getExtentMax() != null) {
            desc.add(intent.getExtentMin() + "-" + intent.getExtentMax() + "平");
        } else if (intent.getExtentMax() != null) {
            desc.add(intent.getExtentMax() + "平以下");
        } else if (intent.getExtentMin() != null) {
            desc.add(intent.getExtentMin() + "平以上");
        }
        if (intent.getFloorMin() != null && intent.getFloorMax() != null) {
            desc.add(intent.getFloorMin() + "-" + intent.getFloorMax() + "楼");
        } else if (intent.getFloorMin() != null) {
            desc.add(intent.getFloorMin() + "楼以上");
        } else if (intent.getFloorMax() != null) {
            desc.add(intent.getFloorMax() + "楼以下");
        }
        if (intent.getMonthlyRentMin() != null && intent.getMonthlyRentMax() != null) {
            desc.add("月租" + formatMoney(intent.getMonthlyRentMin()) + "-" + formatMoney(intent.getMonthlyRentMax()) + "元");
        } else if (intent.getMonthlyRentMax() != null) {
            desc.add("月租" + formatMoney(intent.getMonthlyRentMax()) + "元以内");
        } else if (intent.getMonthlyRentMin() != null) {
            desc.add("月租" + formatMoney(intent.getMonthlyRentMin()) + "元以上");
        }
        String saleText = buildSaleText(intent);
        if (StrUtil.isNotBlank(saleText)) {
            desc.add(saleText);
        }
        if (StrUtil.isNotBlank(intent.getCityKeyword())) {
            desc.add(intent.getCityKeyword());
        }
        if (StrUtil.isNotBlank(intent.getRegionKeyword())) {
            desc.add(intent.getRegionKeyword());
        }
        if (StrUtil.isNotBlank(intent.getHouseType())) {
            desc.add(intent.getHouseType());
        }
        if (StrUtil.isNotBlank(intent.getDecorationType())) {
            desc.add(intent.getDecorationType());
        }
        if (StrUtil.isNotBlank(intent.getSupportingKeyword())) {
            desc.add(intent.getSupportingKeyword());
        }
        return desc;
    }

    private String buildMatchReason(HouseInfo item, HouseAiIntent intent, String matchType) {
        if (HouseAiMatchTypes.EXACT.equals(matchType)) {
            return "符合已表达的找房条件";
        }
        List<String> deviations = new ArrayList<>();
        addRangeDeviation(deviations, "面积", parseDecimal(item.getExtent()),
            toDecimal(intent.getExtentMin()), toDecimal(intent.getExtentMax()), "平");
        addRangeDeviation(deviations, "月租", item.getMonthlyRent(),
            intent.getMonthlyRentMin(), intent.getMonthlyRentMax(), "元/月");
        addRangeDeviation(deviations, "售价", parseDecimal(item.getSalePrice()),
            intent.getSalePriceMin(), intent.getSalePriceMax(), "元");
        addRangeDeviation(deviations, "总价", parseDecimal(item.getTotalPrice()),
            intent.getTotalPriceMin(), intent.getTotalPriceMax(), "元");
        addFloorDeviation(deviations, item.getFloor(), intent);
        addTextDeviation(deviations, "户型", item.getHouseType(), intent.getHouseType());
        addTextDeviation(deviations, "朝向", item.getToward(), intent.getToward());
        addTextDeviation(deviations, "装修", safeText(item.getHouseLabel()) + " "
            + safeText(item.getSupporting()) + " " + safeText(item.getContent()), intent.getDecorationType());
        addTextDeviation(deviations, "配套", safeText(item.getSupporting()) + " "
            + safeText(item.getContent()) + " " + safeText(item.getHouseLabel()), intent.getSupportingKeyword());
        addBooleanDeviation(deviations, "空调", item.getAirConditioningAvailable(), intent.getAirConditioningAvailable());
        addBooleanDeviation(deviations, "停车", item.getParkingAvailable(), intent.getParkingAvailable());
        addTextDeviation(deviations, "水费计费", item.getWaterBillingType(), intent.getWaterBillingType());
        addTextDeviation(deviations, "电费计费", item.getElectricityBillingType(), intent.getElectricityBillingType());
        addRangeDeviation(deviations, "物业费", item.getPropertyFees(), null, intent.getPropertyFeesMax(), "元");
        addRangeDeviation(deviations, "水费单价", item.getWaterUnitPrice(), null, intent.getWaterUnitPriceMax(), "元");
        addRangeDeviation(deviations, "电费单价", item.getElectricityUnitPrice(), null, intent.getElectricityUnitPriceMax(), "元");
        return deviations.isEmpty() ? "整体条件接近您的需求" : "候选偏离：" + String.join("；", deviations);
    }

    private void addRangeDeviation(List<String> deviations, String label, BigDecimal current,
                                   BigDecimal min, BigDecimal max, String unit) {
        if (current == null || withinRange(current, min, max)) {
            return;
        }
        deviations.add(label + formatMoney(current) + unit);
    }

    private void addFloorDeviation(List<String> deviations, String floor, HouseAiIntent intent) {
        if (intent.getFloorMin() == null && intent.getFloorMax() == null) {
            return;
        }
        Integer current = extractFirstInteger(floor);
        if (current == null || (intent.getFloorMin() != null && current < intent.getFloorMin())
            || (intent.getFloorMax() != null && current > intent.getFloorMax())) {
            deviations.add("楼层" + safeText(floor));
        }
    }

    private void addTextDeviation(List<String> deviations, String label, String current, String expected) {
        if (StrUtil.isBlank(expected) || containsNormalized(current, expected)) {
            return;
        }
        deviations.add(label + safeText(current));
    }

    private void addBooleanDeviation(List<String> deviations, String label, Boolean current, Boolean expected) {
        if (expected == null || expected.equals(current)) {
            return;
        }
        deviations.add(label + (Boolean.TRUE.equals(current) ? "可用" : "不可用"));
    }

    private boolean containsNormalized(String current, String expected) {
        return normalizeSearchText(safeText(current)).contains(normalizeSearchText(expected));
    }

    private void addExtentReason(List<String> reasons, HouseInfo item, HouseAiIntent intent) {
        if (intent.getExtentMin() == null && intent.getExtentMax() == null) {
            return;
        }
        BigDecimal current = parseDecimal(item.getExtent());
        if (current == null) {
            return;
        }
        if (withinRange(current, toDecimal(intent.getExtentMin()), toDecimal(intent.getExtentMax()))) {
            reasons.add("面积" + formatMoney(current) + "平，符合需求");
            return;
        }
        BigDecimal target = pickTarget(toDecimal(intent.getExtentMin()), toDecimal(intent.getExtentMax()));
        if (target != null) {
            reasons.add("面积" + formatMoney(current) + "平，接近" + formatMoney(target) + "平");
        }
    }

    private void addRentReason(List<String> reasons, HouseInfo item, HouseAiIntent intent) {
        if (intent.getMonthlyRentMin() == null && intent.getMonthlyRentMax() == null) {
            return;
        }
        BigDecimal current = item.getMonthlyRent();
        if (current == null) {
            return;
        }
        if (withinRange(current, intent.getMonthlyRentMin(), intent.getMonthlyRentMax())) {
            reasons.add("租金" + formatMoney(current) + "元/月，在预算内");
            return;
        }
        if (intent.getMonthlyRentMax() != null && current.compareTo(intent.getMonthlyRentMax()) > 0) {
            BigDecimal overRate = current.subtract(intent.getMonthlyRentMax())
                .multiply(new BigDecimal("100"))
                .divide(intent.getMonthlyRentMax(), 0, RoundingMode.HALF_UP);
            reasons.add("租金超预算约" + overRate.stripTrailingZeros().toPlainString() + "%");
        }
    }

    private void addTextReason(List<String> reasons, String current, String expected, String label) {
        if (StrUtil.isBlank(expected) || StrUtil.isBlank(current)) {
            return;
        }
        if (normalizeSearchText(current).contains(normalizeSearchText(expected))) {
            reasons.add(label + "匹配");
        } else {
            reasons.add(label + "略有差异");
        }
    }

    private boolean withinRange(BigDecimal current, BigDecimal min, BigDecimal max) {
        if (current == null) {
            return false;
        }
        if (min != null && current.compareTo(min) < 0) {
            return false;
        }
        if (max != null && current.compareTo(max) > 0) {
            return false;
        }
        return true;
    }

    private BigDecimal pickTarget(BigDecimal min, BigDecimal max) {
        if (min != null && max != null) {
            return min.add(max).divide(new BigDecimal("2"), 0, RoundingMode.HALF_UP);
        }
        return min != null ? min : max;
    }

    private BigDecimal toDecimal(Integer value) {
        return value == null ? null : new BigDecimal(value);
    }

    private String buildSaleText(HouseAiIntent intent) {
        if (intent.getTradeType() != null && "sale".equals(intent.getTradeType())) {
            if (intent.getTotalPriceMin() != null && intent.getTotalPriceMax() != null) {
                return "总价" + formatMoney(intent.getTotalPriceMin()) + "-" + formatMoney(intent.getTotalPriceMax()) + "元";
            }
            if (intent.getTotalPriceMax() != null) {
                return "总价" + formatMoney(intent.getTotalPriceMax()) + "元以内";
            }
            if (intent.getSalePriceMin() != null && intent.getSalePriceMax() != null) {
                return "售价" + formatMoney(intent.getSalePriceMin()) + "-" + formatMoney(intent.getSalePriceMax()) + "元";
            }
            if (intent.getSalePriceMax() != null) {
                return "售价" + formatMoney(intent.getSalePriceMax()) + "元以内";
            }
        }
        return "";
    }

    private String formatMoney(BigDecimal value) {
        if (value == null) {
            return "";
        }
        return value.stripTrailingZeros().toPlainString();
    }

    private BigDecimal parseDecimal(String raw) {
        if (StrUtil.isBlank(raw)) {
            return null;
        }
        String number = raw.replaceAll("[^0-9.]", "");
        if (StrUtil.isBlank(number)) {
            return null;
        }
        try {
            return new BigDecimal(number);
        } catch (Exception e) {
            return null;
        }
    }

    private String normalizeSearchText(String text) {
        String normalized = normalize(text);
        normalized = replaceHouseNumberPattern(normalized, HOUSE_TYPE_COMPARTMENT_PATTERN, "隔间");
        Matcher matcher = HOUSE_TYPE_ROOM_HALL_PATTERN.matcher(normalized);
        StringBuffer buffer = new StringBuffer();
        while (matcher.find()) {
            String replacement = toChineseHouseNumber(matcher.group(1)) + "室" + toChineseHouseNumber(matcher.group(2)) + "厅";
            matcher.appendReplacement(buffer, Matcher.quoteReplacement(replacement));
        }
        matcher.appendTail(buffer);
        return buffer.toString();
    }

    private String replaceHouseNumberPattern(String text, Pattern pattern, String suffix) {
        Matcher matcher = pattern.matcher(text);
        StringBuffer buffer = new StringBuffer();
        while (matcher.find()) {
            matcher.appendReplacement(buffer, Matcher.quoteReplacement(toChineseHouseNumber(matcher.group(1)) + suffix));
        }
        matcher.appendTail(buffer);
        return buffer.toString();
    }

    private String toChineseHouseNumber(String raw) {
        String value = normalize(raw).replace("两", "二");
        switch (value) {
            case "1":
            case "一":
                return "一";
            case "2":
            case "二":
                return "二";
            case "3":
            case "三":
                return "三";
            case "4":
            case "四":
                return "四";
            case "5":
            case "五":
                return "五";
            case "6":
            case "六":
                return "六";
            case "7":
            case "七":
                return "七";
            case "8":
            case "八":
                return "八";
            case "9":
            case "九":
                return "九";
            case "10":
            case "十":
                return "十";
            default:
                return value;
        }
    }

    private Integer extractFirstInteger(String raw) {
        if (StrUtil.isBlank(raw)) {
            return null;
        }
        Matcher matcher = NUMBER_PATTERN.matcher(raw);
        return matcher.find() ? Integer.valueOf(matcher.group(1)) : null;
    }

    private String safeText(String value) {
        return value == null ? "" : value;
    }

    private String normalize(String text) {
        if (text == null) {
            return "";
        }
        return text.toLowerCase(Locale.ROOT)
            .replace("㎡", "平")
            .replace("平方", "平")
            .replace("m²", "平")
            .replace("m2", "平")
            .replace("Ｍ²", "平")
            .replace("（", "(")
            .replace("）", ")")
            .replace("＋", "+")
            .trim();
    }
}
