package egovframework.com.idgen.impl;

import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.PreparedStatement; // java.sql.PreparedStatement로 임포트
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.sql.DataSource;

import org.springframework.jdbc.datasource.DataSourceUtils;

import egovframework.com.idgen.CustomIdGnrService;
import egovframework.rte.fdl.cmmn.exception.FdlException;
import egovframework.rte.fdl.idgnr.EgovIdGnrStrategy;

public class CustomTableIdGnrServiceImpl implements CustomIdGnrService {

	private long allocatedId;
	private long allocatedMaxId;
	private int blockSize = 10; // 기본값, 필요에 따라 변경
	private DataSource dataSource;
	private String table; // 실제 테이블 이름 (예: IDS)
	private String tableName; // TABLE_NAME 컬럼에서 사용할 값 (예: MSG_ID)
	private String columnName = "NEXT_ID"; // NEXT_ID 컬럼명
	private String prefix;
	private String fillChar = "0"; // 채울 문자 (예: 0)
	private int cipers = 13; // 자리수 (예: 14)
	private boolean applyYear;
	private boolean useBigDecimals = false;

	@Override
	public synchronized List<String> getNextStringId(int count) throws FdlException {
		List<String> idList = new ArrayList<>(count);
		try {
			for (int i = 0; i < count; i++) {
				if (allocatedId >= allocatedMaxId) {
					allocateIdBlock(count);
				}
				long id = allocatedId++;
				idList.add(createStringId(id));
			}
		} catch (Exception e) {
			throw new FdlException("ID Generation Error", e);
		}
		return idList;
	}

	private void allocateIdBlock(int requiredCount) throws SQLException, FdlException {
		Connection conn = DataSourceUtils.getConnection(dataSource);
		try {
			conn.setAutoCommit(false);

			int newBlockSize = Math.max(this.blockSize, requiredCount);

			// SELECT 쿼리 수정
			String query = "SELECT " + columnName + " FROM " + table + " WHERE TABLE_NAME = ? FOR UPDATE";
			try (PreparedStatement stmt = conn.prepareStatement(query)) {
				stmt.setString(1, tableName);
				try (ResultSet rs = stmt.executeQuery()) {
					long oldId = 0;
					if (rs.next()) {
						oldId = rs.getLong(1);
					} else {
						throw new FdlException(
								"ID Generation Error: No record found in " + table + " for TABLE_NAME = " + tableName);
					}

					long newId = oldId + newBlockSize;

					// UPDATE 쿼리 수정
					String update = "UPDATE " + table + " SET " + columnName + " = ? WHERE TABLE_NAME = ? AND "
							+ columnName + " = ?";
					try (PreparedStatement updateStmt = conn.prepareStatement(update)) {
						updateStmt.setLong(1, newId);
						updateStmt.setString(2, tableName);
						updateStmt.setLong(3, oldId);
						int row = updateStmt.executeUpdate();

						if (row == 0) {
							throw new FdlException(
									"ID Generation Error: Failed to update ID. Possible concurrent modification.");
						}
					}

					conn.commit();

					allocatedId = oldId;
					allocatedMaxId = newId;
				}
			} catch (SQLException e) {
				conn.rollback();
				throw e;
			}
		} catch (SQLException e) {
			throw new FdlException("ID Generation Error", e);
		} finally {
			DataSourceUtils.releaseConnection(conn, dataSource);
		}
	}

	private String createStringId(long id) {
		StringBuilder sb = new StringBuilder();
		if (prefix != null) {
			sb.append(prefix);
		}
		if (applyYear) {
			sb.append(new SimpleDateFormat("yyyy").format(new Date()));
		}
		String idStr = String.format("%0" + cipers + "d", id);
		sb.append(idStr);
		return sb.toString();
	}

	// 인터페이스의 다른 메서드 구현 (필요에 따라 UnsupportedOperationException 또는 직접 구현)
	@Override
	public BigDecimal getNextBigDecimalId() throws FdlException {
		throw new UnsupportedOperationException("getNextBigDecimalId is not supported");
	}

	@Override
	public long getNextLongId() throws FdlException {
		throw new UnsupportedOperationException("getNextLongId is not supported");
	}

	@Override
	public int getNextIntegerId() throws FdlException {
		throw new UnsupportedOperationException("getNextIntegerId is not supported");
	}

	@Override
	public short getNextShortId() throws FdlException {
		throw new UnsupportedOperationException("getNextShortId is not supported");
	}

	@Override
	public byte getNextByteId() throws FdlException {
		throw new UnsupportedOperationException("getNextByteId is not supported");
	}

	@Override
	public String getNextStringId() throws FdlException {
		throw new UnsupportedOperationException("getNextStringId is not supported");
	}

	@Override
	public String getNextStringId(String strategyId) throws FdlException {
		throw new UnsupportedOperationException("getNextStringId(String strategyId) is not supported");
	}

	@Override
	public String getNextStringId(EgovIdGnrStrategy strategy) throws FdlException {
		throw new UnsupportedOperationException("getNextStringId(EgovIdGnrStrategy strategy) is not supported");
	}

	// 필요한 setter 메서드들 추가
	public void setDataSource(DataSource dataSource) {
		this.dataSource = dataSource;
	}

	public void setTable(String table) {
		this.table = table;
	}

	public void setTableName(String tableName) {
		this.tableName = tableName;
	}

	public void setColumnName(String columnName) {
		this.columnName = columnName;
	}

	public void setPrefix(String prefix) {
		this.prefix = prefix;
	}

	public void setFillChar(String fillChar) {
		this.fillChar = fillChar;
	}

	public void setCipers(int cipers) {
		this.cipers = cipers;
	}

	public void setApplyYear(boolean applyYear) {
		this.applyYear = applyYear;
	}

	public void setBlockSize(int blockSize) {
		this.blockSize = blockSize;
	}
}
