# ParseGuestsInHouseComplimentaryByShiji.java

    package cloud.wconnect.frontoffice.parsereport.comproom.impl;

    import cloud.wconnect.commonlib.cons.BaseConstant;
    import cloud.wconnect.commonlib.cons.BaseErrorCodeEnum;
    import cloud.wconnect.commonlib.cons.EventBodyParamEnum;
    import cloud.wconnect.commonlib.cons.SystemPlatformEnum;
    import cloud.wconnect.commonlib.exception.BadRequestException;
    import cloud.wconnect.commonlib.exception.InternalServerErrorException;
    import cloud.wconnect.commonlib.exception.ParseReportException;
    import cloud.wconnect.commonlib.pojo.dto.EventBodyDTO;
    import cloud.wconnect.commonlib.pojo.dto.PropertyDTO;
    import cloud.wconnect.commonlib.util.*;
    import cloud.wconnect.frontoffice.cons.EventSubjectEnum;
    import cloud.wconnect.frontoffice.parsereport.comproom.IParseGuestsInHouseComplimentary;
    import cloud.wconnect.frontoffice.pojo.bo.comproom.GuestsInHouseComplimentaryBO;
    import cloud.wconnect.frontoffice.service.AmazonS3Service;
    import cloud.wconnect.sns.http.processor.Sender;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.google.common.collect.Lists;
    import com.google.common.collect.Maps;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.commons.csv.CSVFormat;
    import org.apache.commons.csv.CSVRecord;
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Service;
    import org.springframework.web.multipart.MultipartFile;

    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.util.List;
    import java.util.Map;
    import java.util.Objects;

    /**
     * 解析shiji平台的Guest INH Complimentary报告
     */
    @Slf4j
    @Service
    public class ParseGuestsInHouseComplimentaryByShiji implements IParseGuestsInHouseComplimentary {

        @Autowired
        @Qualifier("3pSender")
        private Sender snsSender;
        @Value("${aws-s3.third-party.key.comp-room.guests-in-house-complimentary}")
        private String s3FilePath;
        @Autowired
        private AmazonS3Service amazonS3Service;
        @Autowired
        private ObjectMapper objectMapper;

        /**
         * 支持的报告来源
         *
         * @param source 报告来源
         * @return boolean
         * @author lichen
         * @date 2025/7/29
         */
        @Override
        public boolean supports(String source) {
            return SystemPlatformEnum.SHI_JI.getDesc().equals(source);
        }

        /**
         * 解析报告
         *
         * @param in 文件流
         * @return java.util.List<cloud.wconnect.frontoffice.pojo.bo.comproom.GuestsInHouseComplimentaryBO>
         * @author lichen
         * @date 2025/7/29
         */
        @Override
        public List<GuestsInHouseComplimentaryBO> parse(InputStream in) throws ParseReportException {
            List<GuestsInHouseComplimentaryBO> result = Lists.newArrayList();

            try (InputStreamReader inputStreamReader = new InputStreamReader(in)) {
                // 读取所有记录到List
                List<CSVRecord> records = CSVFormat.EXCEL.parse(inputStreamReader).getRecords();

                int i = 0;

                // 获取标题行
                CSVRecord titleRecord = records.get(i);
                Integer arrivalDateIndex = CsvFileUtils.getTitleIndex(titleRecord, "Arrival Date");
                Integer departureDateIndex = CsvFileUtils.getTitleIndex(titleRecord, "Departure Date");
                Integer guestNameIndex = CsvFileUtils.getTitleIndex(titleRecord, "Guest Name");
                Integer adultsChildrenIndex = CsvFileUtils.getTitleIndex(titleRecord, "Ad./Ch.");
                Integer roomNumberIndex = CsvFileUtils.getTitleIndex(titleRecord, "Room #");
                Integer roomTypeIndex = CsvFileUtils.getTitleIndex(titleRecord, "Room Type");
                Integer dataNotesContentIndex = CsvFileUtils.getTitleIndex(titleRecord, "DataNotes_Content");
                Integer confirmationNumberIndex = CsvFileUtils.getTitleIndex(titleRecord, "Confirmation Number");

                i++;

                while (i < records.size()) {
                    CSVRecord csvRecord = records.get(i);

                    GuestsInHouseComplimentaryBO bo = new GuestsInHouseComplimentaryBO();

                    // Arrival Date
                    String arrivalDateStr = CsvFileUtils.getByIndex(csvRecord, arrivalDateIndex);
                    if (StringUtils.isBlank(arrivalDateStr)) {
                        i++;
                        continue;
                    }
                    String arrivalDate = DateTimeUtils.localDateToStr(DateTimeUtils.strToLocalDate(arrivalDateStr.substring(0, 8),
                            BaseConstant.DATE_TIME_FORMAT_MM_DD_YY), BaseConstant.DATE_FORMAT_YYYY_MM_DD);
                    bo.setArrivalDate(arrivalDate);

                    // Departure Date
                    String departureDateStr = CsvFileUtils.getByIndex(csvRecord, departureDateIndex);
                    if (StringUtils.isBlank(departureDateStr)) {
                        i++;
                        continue;
                    }
                    String departureDate = DateTimeUtils.localDateToStr(DateTimeUtils.strToLocalDate(departureDateStr.substring(0, 8),
                            BaseConstant.DATE_TIME_FORMAT_MM_DD_YY), BaseConstant.DATE_FORMAT_YYYY_MM_DD);
                    bo.setDepartureDate(departureDate);

                    // Guest Name
                    String guestName = CsvFileUtils.getByIndex(csvRecord, guestNameIndex);
                    bo.setGuestName(guestName);

                    // Adults/Children
                    String adAndCh = CsvFileUtils.getByIndex(csvRecord, adultsChildrenIndex);
                    if (StringUtils.isNotBlank(adAndCh)) {
                        String[] adAndChArr = adAndCh.split("/");
                        // 成年人数
                        Integer adultsNumber = Integer.valueOf(adAndChArr[0].trim());
                        bo.setAdultsNumber(adultsNumber);
                        // 儿童人数
                        Integer childrenNumber = Integer.valueOf(adAndChArr[1].trim());
                        bo.setChildrenNumber(childrenNumber);
                    }

                    // Room #
                    String roomNumber = CsvFileUtils.getByIndex(csvRecord, roomNumberIndex);
                    bo.setRoomNumber(StringUtils.isEmpty(roomNumber) ? "" : roomNumber);

                    // Room Type
                    String roomType = CsvFileUtils.getByIndex(csvRecord, roomTypeIndex);
                    bo.setRoomType(StringUtils.isEmpty(roomType) ? "" : roomType);

                    // Data Notes Content
                    List<String> dataNotesContentList = Lists.newArrayList();
                    if (Objects.nonNull(dataNotesContentIndex)) {
                        /*
                         * 若存在 Data Notes Content 标题，则获取当前行 +3 行的 Confirmation Number 列的内容，
                         * 若内容 = General Notes，则表示有评论数据，否则继续下一行数据的循环
                         */
                        int generalNotesRow = i + 3;
                        // 判断行数是否越界
                        if (generalNotesRow < records.size()) {
                            CSVRecord csvNoteRecord = records.get(generalNotesRow);
                            String generalNotes = CsvFileUtils.getByIndex(csvNoteRecord, confirmationNumberIndex);
                            if ("General Notes".equals(generalNotes)) {
                                String dataNotesContent = CsvFileUtils.getByIndex(csvNoteRecord, dataNotesContentIndex);
                                dataNotesContentList.add(dataNotesContent);

                                i += 3;
                            }
                        }
                    }
                    bo.setCommentList(dataNotesContentList);

                    result.add(bo);

                    i++;
                }

                return result;
            } catch (IOException e) {
                log.error(e.getMessage(), e);
                throw new ParseReportException(BaseErrorCodeEnum.SYSTEM_ERROR.getI18nCode(),
                        BaseErrorCodeEnum.SYSTEM_ERROR.getCode(),
                        "parse shiji [Guest INH Complimentary] report error", e);
            }

        }

        /**
         * 校验文件内容是否合法
         *
         * @param file 文件
         * @return void
         * @author lichen
         * @date 2025/7/29
         */
        @Override
        public void checkFile(MultipartFile file) {
            //校验文件格式
            UploadUtils.checkFileFormat(file, Lists.newArrayList("csv"));
            try (InputStream inputStream = file.getInputStream()) {
                //校验文件节点是否满足需求
                ShijiFileCheckUtils.checkGuestInHouseComplimentary(inputStream);
            } catch (BadRequestException e) {
                throw e;
            } catch (Exception e2) {
                throw new InternalServerErrorException(BaseErrorCodeEnum.SYSTEM_ERROR.getI18nCode(),
                        BaseErrorCodeEnum.SYSTEM_ERROR.getCode(), "check shiji [Guest INH Complimentary] error", e2);
            }
        }

        /**
         * 处理数据
         *
         * @param propertyDTO 资产DTO
         * @param file        文件
         * @param userId      操作人ID
         * @return void
         * @author lichen
         * @date 2025/7/29
         */
        @Override
        public void handleData(PropertyDTO propertyDTO, MultipartFile file, int userId) {
            try {
                String tenantSymbol = propertyDTO.getTenantSymbol();
                String abbr = propertyDTO.getAbbr();

                // 设置事件体
                Map<String, Object> params = Maps.newHashMapWithExpectedSize(6);
                params.put(EventBodyParamEnum.TENANT_SYMBOL.getDesc(), tenantSymbol);
                params.put(EventBodyParamEnum.PROPERTY_ABBR.getDesc(), Lists.newArrayList(abbr));
                params.put(EventBodyParamEnum.SOURCE.getDesc(), SystemPlatformEnum.SHI_JI.getDesc());

                // 上传文件
                String key = tenantSymbol + "/" + abbr + "/" + s3FilePath +
                        UploadUtils.getRandomFileName(file.getOriginalFilename());
                amazonS3Service.uploadFile(file, key);

                snsSender.publish(EventSubjectEnum.GUESTS_IN_HOUSE_COMPLIMENTARY.getSubject(),
                        JsonUtils.convertObjToString(objectMapper, new EventBodyDTO(key, params)));
            } catch (Exception e) {
                throw new InternalServerErrorException(BaseErrorCodeEnum.SYSTEM_ERROR.getI18nCode(),
                        BaseErrorCodeEnum.SYSTEM_ERROR.getCode(), "import shiji [Guest INH Complimentary] report exception", e);
            }
        }

    }