package incheon.ags.ias.dataHoprReg.util;

import incheon.com.cmm.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

/**
 * 데이터 파일 파싱 유틸리티
 */
@Slf4j
public class DataFileParseUtil {

    private DataFileParseUtil() {
        // 유틸리티 클래스
    }

    /**
     * 파일 파싱 (인코딩 자동 감지)
     * @param file 파일
     * @param preferUtf8 UTF-8 우선 여부 (false면 MS949 우선)
     * @param outHeaders 파싱된 헤더를 담을 리스트
     * @return 파싱된 데이터 행 목록
     */
    public static List<List<String>> parseFile(File file, boolean preferUtf8, List<String> outHeaders) throws Exception {
        Charset primaryEncoding = preferUtf8 ? StandardCharsets.UTF_8 : Charset.forName("MS949");
        Charset fallbackEncoding = preferUtf8 ? Charset.forName("MS949") : StandardCharsets.UTF_8;

        return parseFileWithEncoding(file, primaryEncoding, fallbackEncoding, outHeaders);
    }

    /**
     * 파일 파싱 (인코딩 지정)
     */
    public static List<List<String>> parseFileWithEncoding(File file, Charset primaryEncoding,
                                                            Charset fallbackEncoding, List<String> outHeaders) throws Exception {
        List<List<String>> dataList;

        try (BufferedReader reader = new BufferedReader(
                new InputStreamReader(new FileInputStream(file), primaryEncoding))) {
            dataList = parseFileContent(reader, outHeaders);
            log.info("파일 파싱 완료 ({}) - 데이터 행 수: {}", primaryEncoding.name(), dataList.size());
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.warn("{} 인코딩으로 읽기 실패, {}로 재시도: {}", primaryEncoding.name(), fallbackEncoding.name(), e.getMessage());
            outHeaders.clear();
            try (BufferedReader reader = new BufferedReader(
                    new InputStreamReader(new FileInputStream(file), fallbackEncoding))) {
                dataList = parseFileContent(reader, outHeaders);
                log.info("파일 파싱 완료 ({}) - 데이터 행 수: {}", fallbackEncoding.name(), dataList.size());
            } catch (BusinessException e2) {
                throw e2;
            } catch (Exception e2) {
                log.error("{}로도 파일 읽기 실패: {}", fallbackEncoding.name(), e2.getMessage(), e2);
                throw new BusinessException("파일 읽기에 실패했습니다. 파일 인코딩을 확인해주세요.");
            }
        }

        return dataList;
    }

    /**
     * 파일 내용 파싱
     * @param reader 파일 리더
     * @param outHeaders 파싱된 헤더를 담을 리스트 (null이면 헤더 없는 파일로 처리)
     */
    private static List<List<String>> parseFileContent(BufferedReader reader, List<String> outHeaders) throws Exception {
        List<List<String>> dataList = new ArrayList<>();
        String line;
        int processedCount = 0;
        Integer expectedColumnCount = null;
        boolean hasHeader = (outHeaders != null);

        while ((line = reader.readLine()) != null) {
            if (line.trim().isEmpty()) continue;
            processedCount++;

            // BOM 제거
            if (processedCount == 1 && line.startsWith("\uFEFF")) {
                line = line.substring(1);
            }

            // 라인 정리
            if (line.contains("\t")) {
                line = line.replaceFirst("^\\s+", "");
            } else {
                line = line.trim();
            }

            List<String> row = parseLine(line);

            // 첫 번째 행 처리
            if (expectedColumnCount == null) {
                expectedColumnCount = row.size();
                if (hasHeader) {
                    // 헤더가 있는 파일: 첫 행을 헤더로 처리
                    outHeaders.addAll(row);
                    log.info("파일 헤더 ({}개): {}", expectedColumnCount, outHeaders);
                    continue;
                } else {
                    // 헤더가 없는 파일: 첫 행도 데이터로 처리
                    log.info("헤더 없는 파일 - 컬럼 수: {}", expectedColumnCount);
                }
            }

            // 컬럼 개수 검증
            if (row.size() > expectedColumnCount) {
                log.error("컬럼 개수 초과 - {}번째 줄", processedCount);
                throw new BusinessException("데이터 이상으로 등록 실패했습니다.");
            }

            // 부족한 컬럼 채우기
            if (row.size() < expectedColumnCount) {
                int missingCount = expectedColumnCount - row.size();
                for (int i = 0; i < missingCount; i++) {
                    row.add("");
                }
            }

            dataList.add(row);
        }

        return dataList;
    }

    /**
     * 라인 파싱 (구분자 자동 감지: 파이프 > 탭 > 콤마)
     */
    public static List<String> parseLine(String line) {
        List<String> result = new ArrayList<>();

        if (line.contains("|")) {
            // 파이프 구분
            String[] parts = line.split("\\|", -1);
            for (String part : parts) {
                result.add(part.trim());
            }
        } else if (line.contains("\t")) {
            // 탭 구분
            String[] parts = line.split("\t", -1);
            for (String part : parts) {
                result.add(part.trim());
            }
        } else if (line.contains(",")) {
            // CSV (따옴표 처리)
            boolean inQuotes = false;
            StringBuilder current = new StringBuilder();
            for (int i = 0; i < line.length(); i++) {
                char c = line.charAt(i);
                if (c == '"') {
                    inQuotes = !inQuotes;
                } else if (c == ',' && !inQuotes) {
                    result.add(current.toString().trim());
                    current = new StringBuilder();
                } else {
                    current.append(c);
                }
            }
            result.add(current.toString().trim());
        } else {
            result.add(line);
        }

        return result;
    }
}
