package com.nhnkcp.verifonepossample.data

import com.nhnkcp.verifonepossample.utils.ByteUtils.getLRC
import com.nhnkcp.verifonepossample.utils.ByteUtils.toTwoByteArray
import com.nhnkcp.verifonepossample.utils.ByteUtils.write
import java.io.ByteArrayOutputStream

/**
 * 단말연동 시 쓰이는 Command 입니다.
 */
class MakeCommand(
    val request: PaymentRequest // 결제 요청 데이터
) {
    fun getCommand(): ByteArray {
        val body = makeBody()
        val header = makeHeader(body.size)
        val command = header + body
        return command + getLRC(command, command.size)
    }

    private fun makeHeader(length: Int): ByteArray {
        return ByteArrayOutputStream().apply {
            write(CMD_STX) // STX
            write((length + 47).toTwoByteArray()) // 전문길이
            write(0xD0.toByte()) // Command ID
            request.tradeCode?.let { write(it) } // 거래구분
            request.processCode?.let { write(it) }  // 업무구분
            write(" ".repeat(10)) // TID (TID 요청 없을 경우 단말기 TID)
            write("KCP-X990A".padStart(10, '#')) // HW 모델명
            write("230817") // FW 버전
            write("1".padStart(6, '0')) // 단말기 전문추적번호
            write(CMD_FS) // FS
        }.toByteArray()
    }

    private fun makeBody(): ByteArray {
        return ByteArrayOutputStream().apply {
            write() // 거래유형
            write(CMD_FS)
            request.transNo?.takeIf { !request.transCode.isNullOrEmpty() }?.let {
                write("${request.transCode}${0x0F.toChar()}$it")
            } // 식별정보
            write(CMD_FS)
            request.password?.let { write(it) } // 비밀번호
            write(CMD_FS)
            request.installment?.let { write(it) } // 할부 개월 수
            write(CMD_FS)
            request.taxSetting?.let { write(it) } // 복합과세여부
            write(CMD_FS)
            write(request.totalAmount.toString()) // 총 거래 금액
            write(CMD_FS)
            write(request.amount.toString()) // 과세
            write(CMD_FS)
            write(request.dutyFree.toString()) // 면세
            write(CMD_FS)
            write(request.tip.toString()) // 봉사
            write(CMD_FS)
            write(request.tax.toString()) // 세금
            write(CMD_FS)
            request.tradeDate?.let { write(it) }  // 원거래일자
            write(CMD_FS)
            request.approvalNo?.let { write(it) }  // 원승인번호
            write(CMD_FS)
            write() // 원포인트승인번호
            write(CMD_FS)
            write() // 면세유공급구분
            write(CMD_FS)
            write() // 유종코드
            write(CMD_FS)
            write() // 유량
            write(CMD_FS)
            write() // 단가
            write(CMD_FS)
            write() // 외상거래일자
            write(CMD_FS)
            request.printCd?.let { write(it) } // 전표출력여부
            write(CMD_FS)
            request.printOpt?.let { write(it) }  // 전표문구설정
            write(CMD_FS)
            val message = request.printData?.chunked(16)
            message?.getOrNull(0)?.let { write(it) } // 출력문구 1
            write(CMD_FS) // FS_2
            message?.getOrNull(1)?.let { write(it) } // 출력문구 2
            write(CMD_FS) // FS_3
            message?.getOrNull(2)?.let { write(it) } // 출력문구 3
            write(CMD_FS) // FS_4
            message?.getOrNull(3)?.let { write(it) } // 출력문구 4
            write(CMD_FS)
            write() // 서명데이터 요청
            write(CMD_FS)
            request.tradeAmountOpt?.let { write(it) }  // 거래금액 옵션
            write(CMD_FS)
            write() // 예비필드
            write(CMD_FS)
            write() // 서명데이터
            write(CMD_FS)
            request.tradeAmountRate?.let { write(it) }  // 세금계산정보
            write(CMD_FS)
            write() // 사용자 데이터
            write(CMD_FS)
            write() // 가맹점 구분 코드
            write(CMD_FS)
            write() // 가맹점 추가 데이터
            write(CMD_FS)
            write() // 예비필드 1
            write(CMD_FS)
            write() // 예비필드 2
            write(CMD_FS)
            write() // 예비필드 3
            write(CMD_FS)
            request.transNo?.let { write(it) } // 거래번호
            write(CMD_ETX)
        }.toByteArray()
    }

    companion object {
        const val CMD_FS = (0x1C).toByte() // Field Separator
        const val CMD_STX = (0x02).toByte() // Start Of Text
        const val CMD_ETX = (0x03).toByte() // End Of Text
    }
}