package egovframework.util.excel;

import org.apache.poi.ss.usermodel.*;

import java.io.IOException;
import java.io.OutputStream;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

/**
 * 엑셀 파일 생성을 위한 기본 인터페이스
 *
 * <p>이 인터페이스는 엑셀 파일 생성에 필요한 기본 메서드를 정의합니다.
 * 셀 생성, 셀 스타일 설정, 파일 쓰기 등의 공통 기능을 제공합니다.</p>
 *
 * <p><b>주요 기능:</b></p>
 * <ul>
 *   <li>다양한 타입의 데이터를 엑셀 셀로 변환</li>
 *   <li>셀 스타일 생성 (굵기, 폰트 등)</li>
 *   <li>엑셀 파일 출력 (일반/암호화)</li>
 * </ul>
 *
 * @see BaseSxssfExcelFile
 * @author eGovFrame
 */
public interface ExcelFile {

	// ==================== 파일 출력 메서드 ====================

	/**
	 * 엑셀 워크북을 출력 스트림에 씁니다.
	 *
	 * @param stream 출력 스트림
	 * @throws IOException 파일 쓰기 중 오류 발생 시
	 */
	void write(OutputStream stream) throws IOException;

	/**
	 * 엑셀 워크북을 암호화하여 출력 스트림에 씁니다.
	 *
	 * <p>password가 null이면 암호화하지 않고 일반 파일로 작성됩니다.</p>
	 *
	 * @param stream 출력 스트림
	 * @param password 암호화 비밀번호 (null이면 암호화하지 않음)
	 * @throws IOException 파일 쓰기 또는 암호화 중 오류 발생 시
	 */
	void writeWithEncryption(OutputStream stream, String password) throws IOException;

	// ==================== 셀 생성 메서드 ====================

	/**
	 * 엑셀 셀을 생성하고 값과 스타일을 설정합니다.
	 *
	 * <p>이 메서드는 다양한 타입의 데이터를 적절한 엑셀 셀 타입으로 변환합니다:
	 * <ul>
	 *   <li>숫자 타입 (Integer, Long, Double, Float): 숫자 셀</li>
	 *   <li>불린 타입 (Boolean): 불린 셀</li>
	 *   <li>날짜/시간 타입 (LocalDateTime, LocalDate, LocalTime): 포맷된 문자열 셀</li>
	 *   <li>기타 타입: toString() 결과를 문자열 셀로 저장</li>
	 * </ul>
	 * </p>
	 *
	 * <p><b>날짜/시간 포맷:</b></p>
	 * <ul>
	 *   <li>LocalDateTime: "yyyy-MM-dd HH:mm:ss"</li>
	 *   <li>LocalDate: "yyyy-MM-dd"</li>
	 *   <li>LocalTime: "HH:mm:ss"</li>
	 * </ul>
	 *
	 * @param <T> 값의 타입
	 * @param row 셀을 생성할 행
	 * @param column 셀의 컬럼 인덱스 (0부터 시작)
	 * @param value 셀에 저장할 값 (null이면 셀을 생성하지 않음)
	 * @param style 셀에 적용할 스타일
	 */
	default <T> void createCell(Row row, int column, T value, CellStyle style) {
		// null 값도 보더가 보이도록 빈 셀 생성 후 스타일 적용 (NPE 방지)
		Cell cell = row.createCell(column);
		if (value == null) {
			cell.setCellValue("");
			cell.setCellStyle(style);
			return;
		}

		// 타입별로 적절한 셀 값 설정
		if (value instanceof Integer) {
			cell.setCellValue((Integer) value);
		} else if (value instanceof Long) {
			cell.setCellValue((Long) value);
		} else if (value instanceof Double) {
			cell.setCellValue((Double) value);
		} else if (value instanceof Float) {
			cell.setCellValue((Float) value);
		} else if (value instanceof Boolean) {
			cell.setCellValue((Boolean) value);
		} else if (value instanceof LocalDateTime) {
			LocalDateTime dateTime = (LocalDateTime) value;
			cell.setCellValue(dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
		} else if (value instanceof LocalDate) {
			LocalDate date = (LocalDate) value;
			cell.setCellValue(date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
		} else if (value instanceof LocalTime) {
			LocalTime time = (LocalTime) value;
			cell.setCellValue(time.format(DateTimeFormatter.ofPattern("HH:mm:ss")));
		} else {
			cell.setCellValue(value.toString());
		}

		// 스타일 적용
		cell.setCellStyle(style);
	}

	// ==================== 스타일 생성 메서드 ====================

	/**
	 * 셀 스타일을 생성합니다.
	 *
	 * <p>기본적인 셀 스타일을 생성하며, 굵은 폰트 여부를 지정할 수 있습니다.</p>
	 *
	 * @param wb 워크북
	 * @param isBold 굵은 폰트 사용 여부 (true: 굵게, false: 보통)
	 * @return 생성된 셀 스타일
	 */
	default CellStyle createCellStyle(Workbook wb, boolean isBold) {
		CellStyle style = wb.createCellStyle();
		Font font = wb.createFont();
		font.setBold(isBold);
		style.setFont(font);

		// 중요 로직(한글): 생성되는 모든 셀에 대해 실선(THIN) 보더 적용
		// 데이터 셀과 헤더 셀은 본 메서드를 통해 스타일이 생성되므로, 여기서 공통 보더를 지정한다.
		style.setBorderTop(BorderStyle.THIN);
		style.setBorderBottom(BorderStyle.THIN);
		style.setBorderLeft(BorderStyle.THIN);
		style.setBorderRight(BorderStyle.THIN);

		return style;
	}
}
