package com.ffii.fpsms.modules.report.web

import com.ffii.fpsms.modules.report.service.ReportService
import com.ffii.fpsms.modules.report.service.StockTakeVarianceReportService
import org.apache.poi.ss.usermodel.BorderStyle
import org.apache.poi.ss.usermodel.CellStyle
import org.apache.poi.ss.usermodel.DataFormat
import org.apache.poi.ss.usermodel.FillPatternType
import org.apache.poi.ss.usermodel.HorizontalAlignment
import org.apache.poi.ss.usermodel.IndexedColors
import org.apache.poi.ss.usermodel.Row
import org.apache.poi.ss.usermodel.VerticalAlignment
import org.apache.poi.ss.util.CellRangeAddress
import org.apache.poi.ss.util.WorkbookUtil
import org.apache.poi.xssf.usermodel.XSSFWorkbook
import org.springframework.http.HttpHeaders
import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController
import java.io.ByteArrayOutputStream
import java.time.LocalDate
import java.time.LocalTime
import java.time.format.DateTimeFormatter

@RestController
@RequestMapping("/report")
class StockTakeVarianceReportController(
    private val reportService: ReportService,
    private val stockTakeVarianceReportService: StockTakeVarianceReportService,
) {

    /**
     * 產生 Stock Take Variance 報表 PDF
     *
     * 查詢條件與 Stock Ledger 報表保持一致：
     * - stockCategory
     * - itemCode
     * - storeLocation
     * - stockTakeDateStart / stockTakeDateEnd
     */
    @GetMapping("/print-stock-take-variance")
    fun generateStockTakeVarianceReport(
        @RequestParam(required = false) stockCategory: String?,
        @RequestParam(required = false) itemCode: String?,
        @RequestParam(required = false) storeLocation: String?,
        @RequestParam(required = false) stockTakeDateStart: String?,
        @RequestParam(required = false) stockTakeDateEnd: String?,
        @RequestParam(required = false) type: String?,
    ): ResponseEntity<ByteArray> {
        val parameters = mutableMapOf<String, Any>()

        parameters["stockCategory"] = stockCategory ?: "All"
        parameters["stockSubCategory"] = stockCategory ?: "All"
        parameters["itemNo"] = itemCode ?: "All"
        parameters["year"] = LocalDate.now().year.toString()
        parameters["reportDate"] = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))
        parameters["reportTime"] = LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss"))

        parameters["storeLocation"] = storeLocation ?: ""
        parameters["balanceFilterStart"] = ""
        parameters["balanceFilterEnd"] = ""

        parameters["stockTakeDateStart"] = stockTakeDateStart ?: ""
        parameters["stockTakeDateEnd"] = stockTakeDateEnd ?: ""
        parameters["lastInDateEnd"] = ""
        parameters["lastOutDateEnd"] = ""



        val dbData = stockTakeVarianceReportService.searchStockTakeVarianceReport(
            stockCategory = stockCategory,
            itemCode = itemCode,
            storeLocation = storeLocation,
            stockTakeDateStart = stockTakeDateStart,
            stockTakeDateEnd = stockTakeDateEnd,
            type = type,
        )
        val stockTakeDateDisplay = dbData
            .mapNotNull { it["stockTakeDate"] as? String }
            .filter { it.isNotBlank() }
            .maxOrNull()
            ?: ""

        parameters["stockTakeDate"] = stockTakeDateDisplay

        parameters["stockTakeFilterCaption"] = ""

        val pdfBytes = reportService.createPdfResponse(
            "/jasper/StockTakeVarianceReport.jrxml",
            parameters,
            dbData
        )

        val headers = HttpHeaders().apply {
            contentType = MediaType.APPLICATION_PDF
            setContentDispositionFormData("attachment", "StockTakeVarianceReport.pdf")
            set("filename", "StockTakeVarianceReport.pdf")
        }
        return ResponseEntity(pdfBytes, headers, HttpStatus.OK)
    }

    @GetMapping("/print-stock-take-variance-excel")
    fun exportStockTakeVarianceReportExcel(
        @RequestParam(required = false) stockCategory: String?,
        @RequestParam(required = false) itemCode: String?,
        @RequestParam(required = false) storeLocation: String?,
        @RequestParam(required = false) stockTakeDateStart: String?,
        @RequestParam(required = false) stockTakeDateEnd: String?,
        @RequestParam(required = false) type: String?,
    ): ResponseEntity<ByteArray> {
        val dbData = stockTakeVarianceReportService.searchStockTakeVarianceReport(
            stockCategory = stockCategory,
            itemCode = itemCode,
            storeLocation = storeLocation,
            stockTakeDateStart = stockTakeDateStart,
            stockTakeDateEnd = stockTakeDateEnd,
            type = type,
        )

        val excelBytes = createStockTakeVarianceExcel(
            dbData = dbData,
            stockTakeCaption = buildStockTakeCaption(stockTakeDateStart, stockTakeDateEnd, ""),
        )

        val headers = HttpHeaders().apply {
            contentType = MediaType.parseMediaType(
                "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
            )
            setContentDispositionFormData(
                "attachment",
                "StockTakeVarianceReport.xlsx",
            )
            set("filename", "StockTakeVarianceReport.xlsx")
        }

        return ResponseEntity(excelBytes, headers, HttpStatus.OK)
    }

    /**
     * Stock Take Variance 報表 V2：依盤點輪次 + 可選物料編號；僅含已有已完成盤點紀錄之列；審核時間為 approver 之日期時間。
     */
    @GetMapping("/print-stock-take-variance-v2")
    fun generateStockTakeVarianceReportV2(
        @RequestParam(required = false) overall: Boolean?,
        @RequestParam(required = false) stockTakeRoundId: String?,
        @RequestParam(required = false) itemCode: String?,
        @RequestParam(required = false, name = "store_id") storeId: String?,
        @RequestParam(required = false) status: String?,
        @RequestParam(required = false) type: String?,
    ): ResponseEntity<ByteArray> {
        val rep012 = resolveRep012ReportData(overall, stockTakeRoundId, itemCode, storeId, status, type)

        val parameters = mutableMapOf<String, Any>()

        parameters["stockCategory"] = "All"
        parameters["stockSubCategory"] = "All"
        parameters["itemNo"] = itemCode ?: "All"
        parameters["year"] = LocalDate.now().year.toString()
        parameters["reportDate"] = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))
        parameters["reportTime"] = LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss"))

        parameters["storeLocation"] = ""
        parameters["balanceFilterStart"] = ""
        parameters["balanceFilterEnd"] = ""

        parameters["stockTakeDateStart"] = ""
        parameters["stockTakeDateEnd"] = ""
        parameters["lastInDateEnd"] = ""
        parameters["lastOutDateEnd"] = ""

        parameters["stockTakeFilterCaption"] = rep012.caption
        parameters["stockTakeConditionLabel"] = rep012.conditionLabel

        val dbData = rep012.dbData
        val stockTakeDateDisplay = dbData
            .mapNotNull { it["stockTakeDate"] as? String }
            .filter { it.isNotBlank() }
            .maxOrNull()
            ?: ""

        parameters["stockTakeDate"] = stockTakeDateDisplay

        val pdfBytes = reportService.createPdfResponse(
            "/jasper/StockTakeVarianceReport.jrxml",
            parameters,
            dbData
        )

        val headers = HttpHeaders().apply {
            contentType = MediaType.APPLICATION_PDF
            setContentDispositionFormData("attachment", "StockTakeVarianceReport.pdf")
            set("filename", "StockTakeVarianceReport.pdf")
        }
        return ResponseEntity(pdfBytes, headers, HttpStatus.OK)
    }

    @GetMapping("/print-stock-take-variance-v2-excel")
    fun exportStockTakeVarianceReportV2Excel(
        @RequestParam(required = false) overall: Boolean?,
        @RequestParam(required = false) stockTakeRoundId: String?,
        @RequestParam(required = false) itemCode: String?,
        @RequestParam(required = false, name = "store_id") storeId: String?,
        @RequestParam(required = false) status: String?,
        @RequestParam(required = false) type: String?,
    ): ResponseEntity<ByteArray> {
        val rep012 = resolveRep012ReportData(overall, stockTakeRoundId, itemCode, storeId, status, type)
        val cap = rep012.caption
        val dbData = rep012.dbData

        val excelBytes = createStockTakeVarianceExcel(
            dbData = dbData,
            stockTakeCaption = buildStockTakeCaption("", "", cap),
        )

        val headers = HttpHeaders().apply {
            contentType = MediaType.parseMediaType(
                "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
            )
            setContentDispositionFormData(
                "attachment",
                "StockTakeVarianceReport.xlsx",
            )
            set("filename", "StockTakeVarianceReport.xlsx")
        }

        return ResponseEntity(excelBytes, headers, HttpStatus.OK)
    }

    private fun buildStockTakeCaption(
        stockTakeDateStart: String?,
        stockTakeDateEnd: String?,
        stockTakeFilterCaption: String?,
    ): String {
        val cap = stockTakeFilterCaption?.trim().orEmpty()
        if (cap.isNotEmpty()) return cap

        val s = stockTakeDateStart?.trim().orEmpty()
        val e = stockTakeDateEnd?.trim().orEmpty()
        return if (s.isEmpty() && e.isEmpty()) "" else "$s 至 $e"
    }

    private fun createStockTakeVarianceExcel(
        dbData: List<Map<String, Any>>,
        stockTakeCaption: String,
    ): ByteArray {
        val workbook = XSSFWorkbook()
        val reportTitle = "庫存盤點報告"
        val safeSheetName = WorkbookUtil.createSafeSheetName(reportTitle)
        val sheet = workbook.createSheet(safeSheetName)

        val headers = listOf(
            "貨品編號",
            "貨品名稱",
            "單位",
            "批號",
            "到期日",
            "存貨位置",
            "盤點前存量",
            "盤點數",
            "盤盈虧",
            "盤盈虧百分比",
            "類型",
            "審核時間",
        )
        val totalColumns = headers.size
        var rowIndex = 0

        val titleStyle = workbook.createCellStyle().apply {
            alignment = HorizontalAlignment.CENTER
            verticalAlignment = VerticalAlignment.CENTER
            val font = workbook.createFont().apply {
                bold = true
                fontHeightInPoints = 14
            }
            setFont(font)
        }

        val subtitleStyle = workbook.createCellStyle().apply {
            alignment = HorizontalAlignment.LEFT
            verticalAlignment = VerticalAlignment.CENTER
            val font = workbook.createFont().apply {
                bold = true
                fontHeightInPoints = 12
            }
            setFont(font)
        }

        val headerStyle = workbook.createCellStyle().apply {
            alignment = HorizontalAlignment.CENTER
            verticalAlignment = VerticalAlignment.CENTER
            fillForegroundColor = IndexedColors.GREY_25_PERCENT.index
            fillPattern = FillPatternType.SOLID_FOREGROUND
            borderTop = BorderStyle.THIN
            borderBottom = BorderStyle.THIN
            borderLeft = BorderStyle.THIN
            borderRight = BorderStyle.THIN
            val font = workbook.createFont().apply { bold = true }
            setFont(font)
        }

        val textStyle = workbook.createCellStyle().apply {
            alignment = HorizontalAlignment.LEFT
            verticalAlignment = VerticalAlignment.CENTER
            borderTop = BorderStyle.THIN
            borderBottom = BorderStyle.THIN
            borderLeft = BorderStyle.THIN
            borderRight = BorderStyle.THIN
        }

        val centerStyle = workbook.createCellStyle().apply {
            alignment = HorizontalAlignment.CENTER
            verticalAlignment = VerticalAlignment.CENTER
            borderTop = BorderStyle.THIN
            borderBottom = BorderStyle.THIN
            borderLeft = BorderStyle.THIN
            borderRight = BorderStyle.THIN
        }

        val numberStyle = workbook.createCellStyle().apply {
            alignment = HorizontalAlignment.RIGHT
            verticalAlignment = VerticalAlignment.CENTER
            borderTop = BorderStyle.THIN
            borderBottom = BorderStyle.THIN
            borderLeft = BorderStyle.THIN
            borderRight = BorderStyle.THIN
            val df: DataFormat = workbook.createDataFormat()
            dataFormat = df.getFormat("#,##0")
        }

        val dashStyle = workbook.createCellStyle().apply {
            alignment = HorizontalAlignment.RIGHT
            verticalAlignment = VerticalAlignment.CENTER
            borderTop = BorderStyle.THIN
            borderBottom = BorderStyle.THIN
            borderLeft = BorderStyle.THIN
            borderRight = BorderStyle.THIN
        }

        val summaryQtyThickBottomStyle = workbook.createCellStyle().apply {
            alignment = HorizontalAlignment.RIGHT
            verticalAlignment = VerticalAlignment.CENTER
            val df: DataFormat = workbook.createDataFormat()
            dataFormat = df.getFormat("#,##0")
            borderTop = BorderStyle.THICK
            borderBottom = BorderStyle.THICK
            borderLeft = BorderStyle.THIN
            borderRight = BorderStyle.THIN
            val font = workbook.createFont().apply { bold = true }
            setFont(font)
        }

        val summaryLabelThickBottomStyle = workbook.createCellStyle().apply {
            alignment = HorizontalAlignment.RIGHT
            verticalAlignment = VerticalAlignment.CENTER
            borderTop = BorderStyle.THICK
            borderBottom = BorderStyle.THICK
            borderLeft = BorderStyle.THIN
            borderRight = BorderStyle.THIN
            val font = workbook.createFont().apply { bold = true }
            setFont(font)
        }

        val summaryEmptyThickBottomStyle = workbook.createCellStyle().apply {
            alignment = HorizontalAlignment.LEFT
            verticalAlignment = VerticalAlignment.CENTER
            borderTop = BorderStyle.THICK
            borderBottom = BorderStyle.THICK
            borderLeft = BorderStyle.THIN
            borderRight = BorderStyle.THIN
        }

        val summaryHiddenKeyStyle = workbook.createCellStyle().apply {
            alignment = HorizontalAlignment.LEFT
            verticalAlignment = VerticalAlignment.CENTER
            borderTop = BorderStyle.THICK
            borderBottom = BorderStyle.THICK
            borderLeft = BorderStyle.THIN
            borderRight = BorderStyle.THIN
            val font = workbook.createFont().apply { color = IndexedColors.WHITE.index }
            setFont(font)
        }

        // Title
        val titleRow = sheet.createRow(rowIndex++)
        titleRow.createCell(0).apply {
            setCellValue(reportTitle)
            cellStyle = titleStyle
        }
        sheet.addMergedRegion(CellRangeAddress(0, 0, 0, totalColumns - 1))

        // Subtitle: 報告日期 + 盤點條件
        val reportDateTime =
            LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) +
                "(" +
                LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")) +
                ")"
        val subtitleRow = sheet.createRow(rowIndex++)
        subtitleRow.createCell(0).apply {
            setCellValue("報告日期：$reportDateTime")
            cellStyle = subtitleStyle
        }
        sheet.addMergedRegion(CellRangeAddress(1, 1, 0, 2))
        subtitleRow.createCell(3).apply {
            setCellValue(if (stockTakeCaption.isBlank()) "" else "盤點日期：$stockTakeCaption")
            cellStyle = subtitleStyle
        }
        sheet.addMergedRegion(CellRangeAddress(1, 1, 3, totalColumns - 1))

        sheet.createRow(rowIndex++)

        // Column header row
        val headerRowIndex = rowIndex
        val headerRow = sheet.createRow(rowIndex++)
        headers.forEachIndexed { i, h ->
            headerRow.createCell(i).apply {
                setCellValue(h)
                cellStyle = headerStyle
            }
        }

        fun addItemSummaryRow(totalQty: Double, totalStockTakeQty: Double, _itemNo: String, _itemName: String) {
            val r = sheet.createRow(rowIndex++)
            // keep keys for filtering/grouping, visually hidden
            r.createCell(0).apply {
                setCellValue(_itemNo)
                cellStyle = summaryHiddenKeyStyle
            }
            r.createCell(1).apply {
                setCellValue(_itemName)
                cellStyle = summaryHiddenKeyStyle
            }
            r.createCell(2).apply {
                setCellValue("")
                cellStyle = summaryEmptyThickBottomStyle
            }
            // empties until label
            for (c in 3 until totalColumns) {
                r.createCell(c).apply {
                    setCellValue("")
                    cellStyle = summaryEmptyThickBottomStyle
                }
            }

            // place label/value aligned to "盤點前存量"欄附近
            // columns: 0 itemNo, 1 itemName, 2 uom, 3 lotNo, 4 expiry, 5 location, 6 currentBookBalance...
            val labelCol = 5
            val valueCol = 6
            r.getCell(labelCol).apply {
                setCellValue("貨品總量：")
                cellStyle = summaryLabelThickBottomStyle
            }
            r.getCell(valueCol).apply {
                setCellValue(totalQty)
                cellStyle = summaryQtyThickBottomStyle
            }

            // also set "盤點總數" at the "盤點數"欄（col 7）
            r.getCell(7).apply {
                setCellValue(totalStockTakeQty)
                cellStyle = summaryQtyThickBottomStyle
            }
        }

        fun addBlankSeparatorRow() {
            sheet.createRow(rowIndex++)
        }

        if (dbData.isEmpty()) {
            val dataRow = sheet.createRow(rowIndex++)
            for (col in 0 until totalColumns) {
                dataRow.createCell(col).apply {
                    setCellValue("-")
                    cellStyle = textStyle
                }
            }
            addItemSummaryRow(0.0, 0.0, "", "")
        } else {
            var currentItemNo: String? = null
            var currentItemName = ""
            var currentUom = ""
            var currentItemTotalQty = 0.0
            var currentItemTotalStockTakeQty = 0.0

            dbData.forEach { rowMap ->
                val itemNo = rowMap["itemNo"]?.toString().orEmpty()
                val itemName = rowMap["itemName"]?.toString().orEmpty()
                val uom = rowMap["unitOfMeasure"]?.toString().orEmpty()

                if (currentItemNo != null && itemNo != currentItemNo) {
                    addItemSummaryRow(currentItemTotalQty, currentItemTotalStockTakeQty, currentItemNo!!, currentItemName)
                    addBlankSeparatorRow()
                    currentItemTotalQty = 0.0
                    currentItemTotalStockTakeQty = 0.0
                }

                val r = sheet.createRow(rowIndex++)
                setTextCell(r, 0, itemNo, textStyle)
                setTextCell(r, 1, itemName, textStyle)
                setTextCell(r, 2, uom, centerStyle)
                setTextCell(r, 3, rowMap["lotNo"], textStyle)
                setTextCell(r, 4, rowMap["expiryDate"], centerStyle)
                setTextCell(r, 5, rowMap["storeLocation"], centerStyle)
                setNumberCellFromFormatted(r, 6, rowMap["currentBookBalance"], numberStyle, dashStyle)
                setNumberCellFromFormatted(r, 7, rowMap["stockTakeQty"], numberStyle, dashStyle)
                setNumberCellFromFormatted(r, 8, rowMap["variance"], numberStyle, dashStyle)
                setTextCell(r, 9, rowMap["variancePercentage"], dashStyle)
                setTextCell(r, 10, rowMap["type"], centerStyle)
                setTextCell(r, 11, rowMap["stockTakeDate"], centerStyle)

                currentItemNo = itemNo
                currentItemName = itemName
                currentUom = uom
                currentItemTotalQty += parseSignedNumber(rowMap["currentBookBalance"]) ?: 0.0
                currentItemTotalStockTakeQty += parseSignedNumber(rowMap["stockTakeQty"]) ?: 0.0
            }

            addItemSummaryRow(currentItemTotalQty, currentItemTotalStockTakeQty, currentItemNo ?: "", currentItemName)
        }

        val lastRowIndex = rowIndex - 1
        if (lastRowIndex >= headerRowIndex) {
            sheet.setAutoFilter(CellRangeAddress(headerRowIndex, lastRowIndex, 0, 0))
        }

        val widths = intArrayOf(14, 26, 10, 18, 14, 14, 14, 12, 12, 14, 18, 22)
        widths.forEachIndexed { idx, w -> sheet.setColumnWidth(idx, w * 256) }

        val output = ByteArrayOutputStream()
        workbook.use { it.write(output) }
        return output.toByteArray()
    }

    private fun setTextCell(row: Row, col: Int, value: Any?, style: CellStyle) {
        row.createCell(col).apply {
            setCellValue(value?.toString() ?: "")
            cellStyle = style
        }
    }

    private fun parseSignedNumber(value: Any?): Double? {
        val raw = value?.toString()?.trim().orEmpty()
        if (raw.isBlank() || raw == "-" || raw.equals("null", ignoreCase = true)) return null

        // formats used in SQL: "1,234" or "(1,234)" for negative
        val negative = raw.startsWith("(") && raw.endsWith(")")
        val cleaned = raw.removePrefix("(").removeSuffix(")").replace(",", "").trim()
        val n = cleaned.toDoubleOrNull() ?: return null
        return if (negative) -n else n
    }

    private fun setNumberCellFromFormatted(
        row: Row,
        col: Int,
        value: Any?,
        numberStyle: CellStyle,
        dashStyle: CellStyle,
    ) {
        val cell = row.createCell(col)
        val parsed = parseSignedNumber(value)
        if (parsed == null) {
            cell.setCellValue("-")
            cell.cellStyle = dashStyle
            return
        }

        if (parsed < 0) {
            // keep Excel numeric for sorting/filtering; show parentheses via format is non-trivial, so use text
            cell.setCellValue("(${formatAbsInt(parsed)})")
            cell.cellStyle = dashStyle
        } else {
            cell.setCellValue(parsed)
            cell.cellStyle = numberStyle
        }
    }

    private fun formatAbsInt(v: Double): String {
        val abs = kotlin.math.abs(v).toLong()
        return "%,d".format(abs)
    }

    private data class Rep012ReportData(
        val caption: String,
        val conditionLabel: String,
        val dbData: List<Map<String, Any>>,
    )

    private fun parseStockTakeRoundIds(raw: String?): List<Long> =
        raw
            ?.split(",")
            ?.mapNotNull { it.trim().toLongOrNull() }
            ?.distinct()
            ?: emptyList()

    /**
     * rep-012：單輪＝單輪查詢；多輪＝已選輪次內各批號／倉最新已完成（status 固定 completed）。
     * overall=true 且未傳輪次時保留舊「全系統輪次」行為。
     */
    private fun resolveRep012ReportData(
        overall: Boolean?,
        stockTakeRoundId: String?,
        itemCode: String?,
        storeId: String?,
        status: String?,
        type: String?,
    ): Rep012ReportData {
        val roundIds = parseStockTakeRoundIds(stockTakeRoundId)
        val useLegacyOverall = overall == true && roundIds.isEmpty()
        require(useLegacyOverall || roundIds.isNotEmpty()) {
            "stockTakeRoundId is required"
        }

        if (useLegacyOverall) {
            return Rep012ReportData(
                caption = stockTakeVarianceReportService.getStockTakeVarianceOverallCaption(),
                conditionLabel = "盤點條件：",
                dbData = stockTakeVarianceReportService.searchStockTakeVarianceReportV2Overall(
                    itemCode = itemCode,
                    storeId = storeId,
                    type = type,
                ),
            )
        }

        if (roundIds.size == 1) {
            val id = roundIds.first()
            return Rep012ReportData(
                caption = stockTakeVarianceReportService.getStockTakeRoundCaption(id),
                conditionLabel = "盤點輪次：",
                dbData = stockTakeVarianceReportService.searchStockTakeVarianceReportV2(
                    stockTakeRoundId = id,
                    itemCode = itemCode,
                    storeId = storeId,
                    status = status,
                    type = type,
                ),
            )
        }

        return Rep012ReportData(
            caption = stockTakeVarianceReportService.getStockTakeVarianceMultiRoundCaption(roundIds),
            conditionLabel = "盤點條件：",
            dbData = stockTakeVarianceReportService.searchStockTakeVarianceReportV2Overall(
                itemCode = itemCode,
                storeId = storeId,
                limitedToRoundIds = roundIds,
                type = type,
            ),
        )
    }
}

