# DetailedAvailabilityListenerFileParseByShiJiImpl.java

    package cloud.wconnect.rateshop.service.revenue.detailedavailability;

    import cloud.wconnect.commonlib.cons.BaseConstant;
    import cloud.wconnect.commonlib.cons.SystemPlatformEnum;
    import cloud.wconnect.commonlib.pojo.bo.ReportDataBO;
    import cloud.wconnect.commonlib.util.DateTimeUtils;
    import cloud.wconnect.commonlib.util.NumberUtil;
    import cloud.wconnect.rateshop.pojo.bo.revenue.RoomTypeRoomsBO;
    import com.baomidou.dynamic.datasource.annotation.DS;
    import com.google.common.collect.Lists;
    import com.google.common.collect.Maps;
    import org.apache.commons.collections.MapUtils;
    import org.apache.commons.csv.CSVFormat;
    import org.apache.commons.csv.CSVRecord;
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.stereotype.Service;

    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.util.Iterator;
    import java.util.List;
    import java.util.Map;

    /**
     * @author yyt
     * 2025/07/04
     */
    @Service
    @DS("rate_shop")
    public class DetailedAvailabilityListenerFileParseByShiJiImpl implements IDetailedAvailabilityListenerFileParse {

        private static final String SOURCE = SystemPlatformEnum.SHI_JI.getDesc();

        /**
         * 判断支持的平台
         *
         * @param source 平台
         * @return boolean
         * @author yyt
         * @date 2025/07/04
         */
        @Override
        public boolean supports(String source) {
            return SOURCE.equals(source);
        }

        /**
         * 解析报告数据
         *
         * @param propertyId 资产 id
         * @param timeZone   时区
         * @param in         文件流
         * @param startDate  开始日期
         * @param endDate    结束日期
         * @return RoomTypeRoomsBO
         * @author yyt
         * @date 2025/07/04
         */
        @Override
        public ReportDataBO<RoomTypeRoomsBO> parseReportForNext14Days(Integer propertyId, String timeZone, InputStream in,
                                                                      Long startDate, Long endDate) throws Exception {
            // 报告中的数据在处理范围内
            boolean isInScope = false;

            List<RoomTypeRoomsBO> roomTypeRoomsBOS = Lists.newArrayList();

            Iterable<CSVRecord> records = CSVFormat.EXCEL.parse(new InputStreamReader(in));
            // 先取第一行数据，锁定 market code 所属 列
            Iterator<CSVRecord> iterator = records.iterator();
            if (!iterator.hasNext()) return new ReportDataBO<>(isInScope, roomTypeRoomsBOS);

            CSVRecord firstRecord = iterator.next();
            if (firstRecord.size() < 2) return new ReportDataBO<>(isInScope, roomTypeRoomsBOS);

            Map<String, Integer> marketCodeByIndex = Maps.newHashMap();
            for (int i = 2; i < firstRecord.size(); i++) {
                String marketCode = firstRecord.get(i);
                if (StringUtils.isEmpty(marketCode)) continue;
                if (i == firstRecord.size() - 1) break;

                marketCodeByIndex.put(marketCode, i);
            }
            if (MapUtils.isEmpty(marketCodeByIndex)) return new ReportDataBO<>(isInScope, roomTypeRoomsBOS);

            // 解析其他行数据
            for (CSVRecord record : records) {
                // 跳过第一行的标题
                if (record.getRecordNumber() == 1) {
                    continue;
                }

                String date = record.get(0);
                if (StringUtils.isEmpty(date)) continue;
                if (date.equals("Total")) break;

                String dateStr = date.substring(0, 8);
                long dataDate = DateTimeUtils.dateStrToEpochSecond(dateStr, BaseConstant.DATE_TIME_FORMAT_MM_DD_YY, timeZone);
                if (dataDate < startDate || dataDate > endDate) {
                    continue;
                } else {
                    isInScope = true;
                }

                marketCodeByIndex.forEach((marketCode, index) -> {
                    String rooms = NumberUtil.removeComma(record.get(index));
                    roomTypeRoomsBOS.add(new RoomTypeRoomsBO(dataDate, marketCode, (StringUtils.isEmpty(rooms) ? BaseConstant.ZERO : Integer.parseInt(rooms))));
                });
            }

            return new ReportDataBO<>(isInScope, roomTypeRoomsBOS);
        }

    }