<template>
    <div class="default-main bookkeeping-dashboard">
        <section class="dashboard-grid">
            <div class="dashboard-panel bank-panel">
                <div class="panel-title">{{ t('dashboard.Available Bank Balance') }}</div>
                <div class="table-scroll">
                    <table class="bank-table">
                        <thead>
                            <tr>
                                <th>{{ t('dashboard.Bank Name') }}</th>
                                <th>{{ t('dashboard.Current Balance') }}</th>
                                <th>{{ t('dashboard.Transaction Breakdown') }}</th>
                                <th>{{ t('dashboard.Safe Alert') }}</th>
                            </tr>
                        </thead>
                        <tbody>
                            <tr
                                v-for="bank in visibleBanks"
                                :key="bank.id"
                                :class="[bank.rowClass, { 'bank-colored': bank.labelColor }]"
                                :style="bankRowStyle(bank)"
                            >
                                <td>
                                    <strong>{{ bank.name }}</strong>
                                    <small>{{ bank.account }}</small>
                                </td>
                                <td class="balance">AUD {{ money(bank.balance) }}</td>
                                <td>
                                    <div class="bank-operate">
                                        <input :id="calculatorToggleId(bank)" class="calculator-toggle" type="checkbox" />
                                        <div class="bank-operate-main">
                                            <label
                                                class="calculator-button"
                                                :for="calculatorToggleId(bank)"
                                                :aria-label="t('dashboard.Fast Calculation')"
                                                :title="t('dashboard.Fast Calculation')"
                                            >
                                                <Icon name="fa fa-calculator" size="13" color="currentColor" />
                                            </label>
                                            <el-button size="small" :icon="Switch" @click="openTransfer(bank)">
                                                {{ t('dashboard.Transfer') }}
                                            </el-button>
                                            <div class="breakdown">
                                                <div class="breakdown-row breakdown-in">
                                                    <span class="breakdown-label">入</span>
                                                    <span class="breakdown-count">({{ bank.depositCount }})</span>
                                                    <strong>{{ money(bank.deposit) }}</strong>
                                                </div>
                                                <div class="breakdown-row breakdown-out">
                                                    <span class="breakdown-label">出</span>
                                                    <span class="breakdown-count">({{ bank.withdrawCount }})</span>
                                                    <strong>{{ money(bank.withdraw) }}</strong>
                                                </div>
                                            </div>
                                        </div>
                                        <div class="bank-calculator">
                                            <div class="calculator-formula">
                                                <el-input
                                                    v-model="calculatorFormulas[calculatorKey(bank)]"
                                                    class="calculator-input"
                                                    size="small"
                                                    :placeholder="t('dashboard.Calculation placeholder')"
                                                    clearable
                                                />
                                                <span class="calculator-equals">=</span>
                                                <strong class="calculator-result" :class="{ 'is-invalid': isCalculatorInvalid(bank) }">
                                                    {{ calculatorResultText(bank) }}
                                                </strong>
                                            </div>
                                            <div class="calculator-hint">
                                                {{ t('dashboard.Fast Calculation Support') }}
                                                <span>+ − × ÷</span>
                                            </div>
                                        </div>
                                    </div>
                                </td>
                                <td>
                                    <el-tag size="small" effect="plain" :type="bank.alertCode !== '0' ? 'danger' : 'info'">
                                        {{ safeAlertText(bank.alertCode) }}
                                    </el-tag>
                                </td>
                            </tr>
                            <tr v-if="!visibleBanks.length">
                                <td class="empty-banks" colspan="4">{{ t('dashboard.No bank data') }}</td>
                            </tr>
                        </tbody>
                    </table>
                </div>
                <button v-if="banks.length > 4" class="more-info" type="button" @click="showAllBanks = !showAllBanks">
                    {{ showAllBanks ? t('dashboard.Show less') : t('dashboard.More info') }}
                    <Icon :name="showAllBanks ? 'fa fa-caret-up' : 'fa fa-caret-down'" />
                </button>
            </div>

            <aside class="summary-side">
                <div class="dashboard-panel summary-panel">
                    <div class="panel-title">{{ t('dashboard.Customer Summary') }}</div>
                    <dl>
                        <template v-for="item in summary" :key="item.label">
                            <dt>{{ item.label }}:</dt>
                            <dd>{{ item.value }}</dd>
                        </template>
                    </dl>
                </div>
                <el-button class="create-button" type="success" @click="openCreate">{{ t('dashboard.Create New Transaction') }}</el-button>
            </aside>
        </section>

        <el-alert class="webhook-alert" type="warning" :closable="true" show-icon>
            <template #title>
                <strong>{{ t('dashboard.Webhook enabled') }}</strong>
            </template>
            <p>{{ t('dashboard.Webhook hint') }}</p>
        </el-alert>

        <section class="transaction-section">
            <div class="filter-row">
                <div class="date-filter">
                    <label>{{ t('dashboard.Start Date') }}:</label>
                    <el-date-picker v-model="filters.startDate" type="date" value-format="YYYY-MM-DD" />
                    <label>{{ t('dashboard.End Date') }}:</label>
                    <el-date-picker v-model="filters.endDate" type="date" value-format="YYYY-MM-DD" />
                    <el-button @click="search">{{ t('Search') }}</el-button>
                    <el-button @click="setToday">{{ t('dashboard.Today') }}</el-button>
                </div>
                <div class="totals">
                    <span>{{ t('dashboard.Date of data') }}: {{ dateRangeText }}</span>
                    <b
                        >{{ t('dashboard.Total Deposit / IN') }}: <em>AUD {{ money(totalDeposit) }}</em></b
                    >
                    <b
                        >{{ t('dashboard.Total Withdraw / OUT') }}: <em>AUD {{ money(totalWithdraw) }}</em></b
                    >
                </div>
            </div>

            <el-table :data="transactions" border size="small" class="transaction-table" :row-class-name="transactionRowClass">
                <el-table-column prop="createdBy" :label="t('dashboard.Created by')" width="110" />
                <el-table-column prop="createdTime" :label="t('dashboard.Created Time')" width="170" />
                <el-table-column :label="t('dashboard.Category')" width="100">
                    <template #default="{ row }">{{ categoryText(row.categoryId) }}</template>
                </el-table-column>
                <el-table-column prop="username" :label="t('dashboard.Username')" width="110" />
                <el-table-column prop="remark" :label="t('dashboard.Remark')" min-width="205" />
                <el-table-column prop="bank" :label="t('dashboard.Bank')" min-width="165" />
                <el-table-column :label="t('dashboard.Type')" width="95">
                    <template #default="{ row }">{{ typeText(row.typeId) }}</template>
                </el-table-column>
                <el-table-column :label="t('dashboard.Amount (AUD)')" width="130" align="right">
                    <template #default="{ row }">
                        <strong :class="row.flow === 'in' ? 'amount-in' : 'amount-out'">{{ money(row.amount) }}</strong>
                    </template>
                </el-table-column>
                <el-table-column :label="t('dashboard.Label')" width="100">
                    <template #default="{ row }">{{ transactionLabelText(row.labelId) }}</template>
                </el-table-column>
                <el-table-column :label="t('dashboard.Game Ticket')" min-width="140">
                    <template #default="{ row }">
                        <div v-for="(ticket, index) in row.ticket" :key="`${ticket}-${index}`">{{ ticket }}</div>
                    </template>
                </el-table-column>
                <el-table-column :label="t('dashboard.Action')" fixed="right" width="180">
                    <template #default="{ row }">
                        <el-button link type="primary" size="small" @click="openHistory(row)">{{ t('dashboard.History') }}</el-button>
                        <el-button link type="primary" size="small" @click="openEdit(row)">{{ t('Edit') }}</el-button>
                        <el-button link type="danger" size="small" @click="removeTransaction(row)">{{ t('Delete') }}</el-button>
                    </template>
                </el-table-column>
            </el-table>

            <div class="pagination">
                <el-pagination
                    v-model:current-page="transactionPage.currentPage"
                    background
                    layout="prev, pager, next"
                    :total="transactionPage.count"
                    :page-size="transactionPage.pageSize"
                    @current-change="onTransactionPageChange"
                />
            </div>
        </section>

        <el-dialog v-model="transactionDialog.visible" :title="transactionDialogTitle" width="680px">
            <el-form :model="transactionForm" label-width="145px">
                <el-form-item :label="t('dashboard.Date & Time')">
                    <el-date-picker v-model="transactionForm.time" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" />
                    <el-radio-group v-model="transactionForm.timeMode" class="inline-mode">
                        <el-radio value="Auto">{{ t('dashboard.Auto') }}</el-radio>
                        <el-radio value="Manual">{{ t('dashboard.Manual') }}</el-radio>
                    </el-radio-group>
                </el-form-item>
                <el-form-item :label="t('dashboard.Category')">
                    <el-select v-model="transactionForm.category">
                        <el-option :label="t('dashboard.Customer')" :value="1" />
                        <el-option :label="t('dashboard.Other Adjust')" :value="2" />
                    </el-select>
                </el-form-item>
                <el-form-item :label="t('dashboard.Type')">
                    <el-radio-group v-model="transactionForm.type">
                        <el-radio-button :value="1">{{ t('dashboard.Deposit') }}</el-radio-button>
                        <el-radio-button :value="2">{{ t('dashboard.Withdraw') }}</el-radio-button>
                        <el-radio-button :value="3">IN</el-radio-button>
                        <el-radio-button :value="4">OUT</el-radio-button>
                    </el-radio-group>
                </el-form-item>
                <el-form-item :label="t('dashboard.Username')">
                    <el-input
                        v-model="transactionForm.username"
                        :disabled="transactionDialog.mode === 'edit'"
                        :placeholder="t('dashboard.Username placeholder')"
                    />
                </el-form-item>
                <el-form-item :label="t('dashboard.Remark')">
                    <el-input v-model="transactionForm.remark" :placeholder="t('dashboard.Optional')" />
                </el-form-item>
                <el-form-item :label="t('dashboard.Amount (AUD)')">
                    <el-input-number v-model="transactionForm.amount" :min="0" :precision="2" />
                </el-form-item>
                <el-form-item :label="t('dashboard.Bank')">
                    <el-select v-model="transactionForm.bank" :placeholder="t('dashboard.Optional select')">
                        <el-option v-for="bank in banks" :key="bank.id" :label="bank.name" :value="bank.id" />
                    </el-select>
                </el-form-item>
                <el-form-item :label="t('dashboard.Label')">
                    <el-select v-model="transactionForm.label" :placeholder="t('dashboard.Optional select')">
                        <el-option :label="t('dashboard.First Deposit')" :value="1" />
                        <el-option :label="t('dashboard.Unclaim')" :value="2" />
                    </el-select>
                </el-form-item>
                <el-form-item :label="t('dashboard.Game Ticket Auto')">
                    <el-checkbox v-model="transactionForm.ticketAuto">{{ t('dashboard.Auto generate ticket') }}</el-checkbox>
                </el-form-item>
            </el-form>
            <template #footer>
                <el-button type="primary" :loading="transactionDialog.loading" @click="submitTransaction">{{ t('Confirm') }}</el-button>
                <el-button @click="transactionDialog.visible = false">{{ t('Cancel') }}</el-button>
            </template>
        </el-dialog>

        <el-dialog v-model="historyDialog.visible" :title="t('dashboard.Transaction Edit History')" width="720px">
            <p class="dialog-note">{{ t('dashboard.History retention note') }}</p>
            <el-table v-loading="historyDialog.loading" :data="historyDialog.rows" border size="small" :empty-text="t('dashboard.No Record')">
                <el-table-column prop="id" :label="t('dashboard.Tx ID')" width="100" />
                <el-table-column prop="editedBy" :label="t('dashboard.Edit By')" width="120" />
                <el-table-column prop="editedTime" :label="t('dashboard.Edit Time')" width="170" />
                <el-table-column :label="t('dashboard.Changes')">
                    <template #default="{ row }">{{ historyChangeText(row) }}</template>
                </el-table-column>
            </el-table>
            <template #footer>
                <el-button @click="historyDialog.visible = false">{{ t('Cancel') }}</el-button>
            </template>
        </el-dialog>

        <el-dialog v-model="transferDialog.visible" :title="t('dashboard.Bank Transfer')" width="560px">
            <el-form :model="transferForm" label-width="125px">
                <el-form-item :label="t('dashboard.Transfer (From)')">
                    <el-input v-model="transferForm.fromName" disabled />
                </el-form-item>
                <el-form-item :label="t('dashboard.Transfer (To)')">
                    <el-select v-model="transferForm.bankTo" :placeholder="t('dashboard.Select Bank')">
                        <el-option
                            v-for="bank in banks"
                            :key="bank.id"
                            :label="bank.name"
                            :value="bank.id"
                            :disabled="bank.id === transferForm.bankFrom"
                        />
                    </el-select>
                </el-form-item>
                <el-form-item :label="t('dashboard.Amount')">
                    <el-input-number v-model="transferForm.money" :min="0" :precision="2" />
                </el-form-item>
                <el-form-item :label="t('dashboard.Remark')">
                    <el-input v-model="transferForm.remark" :placeholder="t('dashboard.Optional')" />
                </el-form-item>
            </el-form>
            <template #footer>
                <el-button type="primary" :loading="transferDialog.loading" @click="submitBankTransfer">{{ t('Confirm') }}</el-button>
                <el-button @click="transferDialog.visible = false">{{ t('Cancel') }}</el-button>
            </template>
        </el-dialog>
    </div>
</template>

<script setup lang="ts">
import { Switch } from '@element-plus/icons-vue'
import { computed, onMounted, reactive, ref } from 'vue'
import { useI18n } from 'vue-i18n'
import { bankTransact, delTransact, editTransact, index as getDashboard, logHistory, newTransact } from '/@/api/backend/dashboard'
import type { DashboardTransactPayload } from '/@/api/backend/dashboard'

defineOptions({
    name: 'dashboard',
})

const { t } = useI18n()

interface Bank {
    id: number | string
    name: string
    account: string
    balance: number
    deposit: number
    withdraw: number
    depositCount: number
    withdrawCount: number
    alertCode: string
    rowClass?: string
    labelColor?: string
}

interface DashboardBank {
    id: number | string
    bank_name?: string
    bank_account?: string
    balance?: number | string
    current_balance?: number | string
    tx_in?: number | string
    tx_out?: number | string
    fund_in?: number | string
    fund_out?: number | string
    total_fund_in?: number | string
    total_fund_out?: number | string
    count_fund_in?: number | string
    count_fund_out?: number | string
    deposit_count?: number | string
    withdraw_count?: number | string
    safe_alert?: number | string
    status?: number | string
    label_color?: string
}

interface Transaction {
    id: number
    createdBy: string
    createdTime: string
    categoryId: string
    username: string
    remark: string
    bank: string
    bankId: number | string
    typeId: string
    flow: 'in' | 'out'
    amount: number
    labelId: string
    ticket: string[]
}

interface DashboardScoreLog {
    game_type_text?: string
    money_log_id?: number | string
    game_type?: number | string
    score?: number | string
}

interface DashboardTransaction {
    id: number
    user_id?: number | string
    money?: number | string
    before?: number | string
    after?: number | string
    type?: number | string
    transaction_id?: string
    created_by?: string
    memo?: string
    create_time?: number | string
    bank_id?: number | string
    category?: number | string
    user_name?: string
    bank_name?: string
    label?: number | string
    scoreLog?: DashboardScoreLog[]
}

interface DashboardTransactionPage {
    count?: number | string
    current_page?: number | string
    last_page?: number | string
    list?: DashboardTransaction[]
    total_deposit?: number | string
    total_withdraw?: number | string
}

interface DashboardCustomerSummary {
    total_deposit?: number | string
    total_withdraw?: number | string
    count_deposit?: number | string
    count_withdraw?: number | string
    active_player?: number | string
    first_deposit?: number | string
    unclaim_amount?: number | string
    unclaim_receipt?: number | string
}

interface HistoryRow {
    id: number | string
    editedBy: string
    editedTime: string
    bankBefore: string
    bankAfter: string
}

interface CalculationResult {
    valid: boolean
    value: number
}

const today = () => {
    const date = new Date()
    const pad = (value: number) => value.toString().padStart(2, '0')
    return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`
}

const money = (value: number) =>
    Number(value).toLocaleString('en-AU', {
        minimumFractionDigits: 2,
        maximumFractionDigits: 2,
    })

const toNumber = (value: unknown) => {
    const number = Number(value)
    return Number.isFinite(number) ? number : 0
}

const normalizeCalculationFormula = (value: string) =>
    value
        .replace(/,/g, '')
        .replace(/乘以/g, '*')
        .replace(/除以/g, '/')
        .replace(/加/g, '+')
        .replace(/减/g, '-')
        .replace(/[＋]/g, '+')
        .replace(/[－–—]/g, '-')
        .replace(/[×＊xX]/g, '*')
        .replace(/[÷／]/g, '/')
        .replace(/\s+/g, '')
        .replace(/^=/, '')

const evaluateExpression = (expression: string) => {
    let index = 0

    const parseNumber = () => {
        const matched = expression.slice(index).match(/^(?:\d+(?:\.\d*)?|\.\d+)/)
        if (!matched) return null

        index += matched[0].length
        return Number(matched[0])
    }

    const parseFactor = (): number | null => {
        const char = expression[index]

        if (char === '+') {
            index += 1
            return parseFactor()
        }

        if (char === '-') {
            index += 1
            const value = parseFactor()
            return value === null ? null : -value
        }

        if (char === '(') {
            index += 1
            const value = parseExpression()

            if (value === null || expression[index] !== ')') return null

            index += 1
            return value
        }

        return parseNumber()
    }

    const parseTerm = (): number | null => {
        let value = parseFactor()
        if (value === null) return null

        while (expression[index] === '*' || expression[index] === '/') {
            const operator = expression[index]
            index += 1
            const right = parseFactor()

            if (right === null) return null

            value = operator === '*' ? value * right : right === 0 ? Number.NaN : value / right
        }

        return value
    }

    function parseExpression(): number | null {
        let value = parseTerm()
        if (value === null) return null

        while (expression[index] === '+' || expression[index] === '-') {
            const operator = expression[index]
            index += 1
            const right = parseTerm()

            if (right === null) return null

            value = operator === '+' ? value + right : value - right
        }

        return value
    }

    const result = parseExpression()

    return result !== null && index === expression.length && Number.isFinite(result) ? result : null
}

const calculateBalancePreview = (balance: number, formula: string): CalculationResult => {
    const normalized = normalizeCalculationFormula(formula)

    if (!normalized) {
        return { valid: true, value: balance }
    }

    if (!/^[\d+\-*/().]+$/.test(normalized)) {
        return { valid: false, value: balance }
    }

    const expression = /^[+\-*/]/.test(normalized) ? `${balance}${normalized}` : `${balance}+${normalized}`
    const value = evaluateExpression(expression)

    return value === null ? { valid: false, value: balance } : { valid: true, value }
}

const clampRgbChannel = (value: number) => Math.min(255, Math.max(0, Math.round(value)))

const parseColorChannel = (value: string) => {
    const number = Number(value)
    return Number.isFinite(number) ? clampRgbChannel(number) : 0
}

const parseAlphaChannel = (value?: string) => {
    if (value === undefined) return 1

    const number = Number(value)
    return Number.isFinite(number) ? Math.min(1, Math.max(0, number)) : 1
}

const parseColorToRgb = (value: string) => {
    const color = value.trim()
    const hex = color.match(/^#([0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8})$/i)

    if (hex) {
        const raw = hex[1]
        const full =
            raw.length === 3
                ? raw
                      .split('')
                      .map((char) => char + char)
                      .join('')
                : raw

        return {
            r: Number.parseInt(full.slice(0, 2), 16),
            g: Number.parseInt(full.slice(2, 4), 16),
            b: Number.parseInt(full.slice(4, 6), 16),
            a: full.length === 8 ? Number.parseInt(full.slice(6, 8), 16) / 255 : 1,
        }
    }

    const rgb = color.match(/^rgba?\(\s*([\d.]+)\s*,\s*([\d.]+)\s*,\s*([\d.]+)(?:\s*,\s*([\d.]+))?\s*\)$/i)

    if (!rgb) return null

    return {
        r: parseColorChannel(rgb[1]),
        g: parseColorChannel(rgb[2]),
        b: parseColorChannel(rgb[3]),
        a: parseAlphaChannel(rgb[4]),
    }
}

const rgbToCss = (rgb: { r: number; g: number; b: number }) => `rgb(${clampRgbChannel(rgb.r)}, ${clampRgbChannel(rgb.g)}, ${clampRgbChannel(rgb.b)})`

const mixRgb = (source: { r: number; g: number; b: number }, target: { r: number; g: number; b: number }, targetWeight: number) => ({
    r: source.r * (1 - targetWeight) + target.r * targetWeight,
    g: source.g * (1 - targetWeight) + target.g * targetWeight,
    b: source.b * (1 - targetWeight) + target.b * targetWeight,
})

const polishedBankRowColor = (backgroundColor: string) => {
    const rgb = parseColorToRgb(backgroundColor)
    if (!rgb) return backgroundColor

    const blended = {
        r: rgb.r * rgb.a + 255 * (1 - rgb.a),
        g: rgb.g * rgb.a + 255 * (1 - rgb.a),
        b: rgb.b * rgb.a + 255 * (1 - rgb.a),
    }
    const max = Math.max(blended.r, blended.g, blended.b)
    const min = Math.min(blended.r, blended.g, blended.b)

    if (max - min < 18) {
        return rgbToCss(mixRgb(blended, { r: 241, g: 245, b: 249 }, 0.72))
    }

    if (blended.g >= blended.r && blended.g >= blended.b) {
        return '#d9f3e5'
    }

    if (blended.r >= blended.g && blended.r >= blended.b) {
        return '#f8dde2'
    }

    return '#dbeafe'
}

const srgbToLinear = (channel: number) => {
    const value = channel / 255
    return value <= 0.03928 ? value / 12.92 : Math.pow((value + 0.055) / 1.055, 2.4)
}

const relativeLuminance = (rgb: { r: number; g: number; b: number }) =>
    0.2126 * srgbToLinear(rgb.r) + 0.7152 * srgbToLinear(rgb.g) + 0.0722 * srgbToLinear(rgb.b)

const contrastRatio = (first: number, second: number) => {
    const lighter = Math.max(first, second)
    const darker = Math.min(first, second)
    return (lighter + 0.05) / (darker + 0.05)
}

const readableTextColor = (backgroundColor: string) => {
    const rgb = parseColorToRgb(backgroundColor)
    if (!rgb) return '#172033'

    const blended = {
        r: rgb.r * rgb.a + 255 * (1 - rgb.a),
        g: rgb.g * rgb.a + 255 * (1 - rgb.a),
        b: rgb.b * rgb.a + 255 * (1 - rgb.a),
    }
    const luminance = relativeLuminance(blended)
    const slateContrast = contrastRatio(luminance, relativeLuminance({ r: 23, g: 32, b: 51 }))
    const whiteContrast = contrastRatio(luminance, 1)
    const darkContrast = contrastRatio(luminance, 0)

    if (slateContrast >= 4.5 || slateContrast >= whiteContrast) {
        return '#172033'
    }

    return whiteContrast >= darkContrast ? '#ffffff' : '#000000'
}

const bankRowStyle = (bank: Bank): Record<string, string> => {
    if (!bank.labelColor) return {}

    const backgroundColor = polishedBankRowColor(bank.labelColor)
    const textColor = readableTextColor(backgroundColor)
    const isLightText = textColor === '#ffffff'

    return {
        backgroundColor,
        '--bank-row-text-color': textColor,
        '--bank-row-muted-color': isLightText ? 'rgba(255, 255, 255, 0.82)' : 'rgba(0, 0, 0, 0.72)',
        '--bank-row-border-color': isLightText ? 'rgba(255, 255, 255, 0.24)' : 'rgba(0, 0, 0, 0.16)',
        '--bank-row-control-bg': isLightText ? 'rgba(255, 255, 255, 0.16)' : 'rgba(255, 255, 255, 0.72)',
        '--bank-row-control-hover-bg': isLightText ? 'rgba(255, 255, 255, 0.26)' : 'rgba(255, 255, 255, 0.88)',
    }
}

const formatDateTime = (value: unknown) => {
    if (typeof value === 'string' && value.trim() && !Number.isFinite(Number(value))) {
        return value
    }

    const timestamp = toNumber(value)
    if (!timestamp) return ''

    const date = new Date(timestamp * 1000)
    const pad = (number: number) => number.toString().padStart(2, '0')
    return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`
}

const mapBank = (bank: DashboardBank): Bank => {
    const fundIn = toNumber(bank.total_fund_in ?? bank.fund_in)
    const fundOut = toNumber(bank.total_fund_out ?? bank.fund_out)
    const safeAlert = String(bank.safe_alert ?? '0')

    return {
        id: bank.id,
        name: bank.bank_name || '-',
        account: bank.bank_account || '',
        balance: toNumber(bank.current_balance ?? bank.balance ?? fundIn - fundOut),
        deposit: fundIn,
        withdraw: fundOut,
        depositCount: toNumber(bank.count_fund_in ?? bank.deposit_count ?? bank.tx_in),
        withdrawCount: toNumber(bank.count_fund_out ?? bank.withdraw_count ?? bank.tx_out),
        alertCode: safeAlert,
        rowClass: String(bank.status ?? '1') === '0' ? 'bank-muted' : '',
        labelColor: bank.label_color || '',
    }
}

const banks = ref<Bank[]>([])
const transactions = ref<Transaction[]>([])
const customerSummary = reactive({
    totalDeposit: 0,
    totalWithdraw: 0,
    countDeposit: 0,
    countWithdraw: 0,
    activePlayer: 0,
    firstDeposit: 0,
    unclaimAmount: 0,
    unclaimReceipt: 0,
})
const transactionTotals = reactive({
    totalDeposit: 0,
    totalWithdraw: 0,
})

const filters = reactive({
    startDate: today(),
    endDate: today(),
})
const transactionPage = reactive({
    count: 0,
    currentPage: 1,
    lastPage: 1,
    pageSize: 10,
})
const showAllBanks = ref(false)
const calculatorFormulas = reactive<Record<string, string>>({})
const visibleBanks = computed(() => (showAllBanks.value ? banks.value : banks.value.slice(0, 4)))
const totalDeposit = computed(() => transactionTotals.totalDeposit)
const totalWithdraw = computed(() => transactionTotals.totalWithdraw)
const dateRangeText = computed(() => {
    const start = new Date(`${filters.startDate}T00:00:00`)
    const end = new Date(`${filters.endDate}T00:00:00`)
    const diffDays = Math.max(1, Math.floor((end.getTime() - start.getTime()) / 86400000) + 1)
    return t('dashboard.Date range', {
        start: filters.startDate,
        end: filters.endDate,
        days: diffDays,
        unit: t(diffDays === 1 ? 'dashboard.Day' : 'dashboard.Days'),
    })
})
const summary = computed(() => [
    { label: t('dashboard.Total Deposit / IN'), value: `AUD ${money(customerSummary.totalDeposit)}` },
    { label: t('dashboard.Total Withdraw / OUT'), value: `AUD ${money(customerSummary.totalWithdraw)}` },
    { label: t('dashboard.Deposit Count'), value: customerSummary.countDeposit },
    { label: t('dashboard.Withdraw Count'), value: customerSummary.countWithdraw },
    { label: t('dashboard.Active Player'), value: customerSummary.activePlayer },
    { label: t('dashboard.First Deposit Player'), value: customerSummary.firstDeposit },
    { label: t('dashboard.Unclaimed Amount'), value: `AUD ${money(customerSummary.unclaimAmount)}` },
    { label: t('dashboard.Unclaimed Receipt'), value: customerSummary.unclaimReceipt },
])

const calculatorKey = (bank: Bank) => String(bank.id)

const calculatorToggleId = (bank: Bank) => `bank-calculator-${calculatorKey(bank).replace(/[^a-zA-Z0-9_-]/g, '-')}`

const calculatorResult = (bank: Bank) => calculateBalancePreview(bank.balance, calculatorFormulas[calculatorKey(bank)] || '')

const isCalculatorInvalid = (bank: Bank) => !calculatorResult(bank).valid

const calculatorResultText = (bank: Bank) => {
    const result = calculatorResult(bank)
    return result.valid ? `AUD ${money(result.value)}` : 'AUD --'
}

const transactionDialog = reactive<{ visible: boolean; loading: boolean; mode: 'create' | 'edit'; editId: number | string | '' }>({
    visible: false,
    loading: false,
    mode: 'create',
    editId: '',
})
const transactionDialogTitle = computed(() =>
    transactionDialog.mode === 'edit' ? t('dashboard.Edit Transaction', { id: transactionDialog.editId }) : t('dashboard.Create New Transaction')
)
const transactionForm = reactive({
    time: '',
    timeMode: 'Auto',
    category: 1,
    type: 1,
    username: '',
    remark: '',
    amount: 0,
    bank: '',
    label: '',
    ticketAuto: true,
})
const historyDialog = reactive({
    visible: false,
    loading: false,
    rows: [] as HistoryRow[],
})
const transferDialog = reactive({ visible: false, loading: false })
const transferForm = reactive<{ bankFrom: Bank['id'] | ''; fromName: string; bankTo: Bank['id'] | ''; money: number; remark: string }>({
    bankFrom: '',
    fromName: '',
    bankTo: '',
    money: 0,
    remark: '',
})

const safeAlertText = (code: string) => {
    const labels: Record<string, string> = {
        '1': t('dashboard.Hourly Alert'),
        '2': t('dashboard.Daily Alert'),
        '3': t('dashboard.Weekly Alert'),
        '4': t('dashboard.Monthly Alert'),
        '5': t('dashboard.Yearly Alert'),
        '6': t('dashboard.Lifetime Alert'),
    }
    return labels[code] || t('dashboard.No Alert')
}

const typeText = (type: string) => {
    const labels: Record<string, string> = {
        '1': t('dashboard.Deposit'),
        '2': t('dashboard.Withdraw'),
        '3': 'IN',
        '4': 'OUT',
    }
    return labels[type] || type
}

const categoryText = (category: string) => {
    const labels: Record<string, string> = {
        '1': t('dashboard.Customer'),
        '2': t('dashboard.Other Adjust'),
    }
    return labels[category] || category
}

const transactionLabelText = (label: string) => {
    const labels: Record<string, string> = {
        '1': t('dashboard.First Deposit'),
        '2': t('dashboard.Unclaim'),
    }
    return labels[label] || ''
}

const mapTransaction = (transaction: DashboardTransaction): Transaction => {
    const type = String(transaction.type ?? '')
    return {
        id: transaction.id,
        createdBy: transaction.created_by || '',
        createdTime: formatDateTime(transaction.create_time),
        categoryId: String(transaction.category ?? ''),
        username: transaction.user_name || '',
        remark: transaction.memo || '',
        bank: transaction.bank_name || '',
        bankId: transaction.bank_id || '',
        typeId: type,
        flow: ['1', '3'].includes(type) ? 'in' : 'out',
        amount: toNumber(transaction.money),
        labelId: String(transaction.label ?? ''),
        ticket: Array.isArray(transaction.scoreLog)
            ? transaction.scoreLog.map((score) => `${score.game_type_text || ''} : ${score.score ?? ''}`).filter((score) => score.trim() !== ':')
            : [],
    }
}

const loadDashboard = (page = transactionPage.currentPage) => {
    return getDashboard({
        start: filters.startDate,
        end: filters.endDate,
        page,
    }).then((res) => {
        const bankData = Array.isArray(res.data.bank) ? res.data.bank : res.data.bank?.list
        banks.value = Array.isArray(bankData) ? bankData.map(mapBank) : []

        const transactionData = res.data.transaction as DashboardTransactionPage | undefined
        const transactionList = Array.isArray(transactionData?.list) ? transactionData.list : []
        transactions.value = transactionList.map(mapTransaction)
        transactionPage.count = toNumber(transactionData?.count)
        transactionPage.currentPage = toNumber(transactionData?.current_page) || page
        transactionPage.lastPage = toNumber(transactionData?.last_page) || 1
        transactionPage.pageSize = transactionPage.lastPage > 0 ? Math.max(1, Math.ceil(transactionPage.count / transactionPage.lastPage)) : 10
        transactionTotals.totalDeposit = toNumber(transactionData?.total_deposit)
        transactionTotals.totalWithdraw = toNumber(transactionData?.total_withdraw)

        const customerData = res.data.customer as DashboardCustomerSummary | undefined
        customerSummary.totalDeposit = toNumber(customerData?.total_deposit)
        customerSummary.totalWithdraw = toNumber(customerData?.total_withdraw)
        customerSummary.countDeposit = toNumber(customerData?.count_deposit)
        customerSummary.countWithdraw = toNumber(customerData?.count_withdraw)
        customerSummary.activePlayer = toNumber(customerData?.active_player)
        customerSummary.firstDeposit = toNumber(customerData?.first_deposit)
        customerSummary.unclaimAmount = toNumber(customerData?.unclaim_amount)
        customerSummary.unclaimReceipt = toNumber(customerData?.unclaim_receipt)
    })
}

const resetTransactionForm = () => {
    Object.assign(transactionForm, {
        time: '',
        timeMode: 'Auto',
        category: 1,
        type: 1,
        username: '',
        remark: '',
        amount: 0,
        bank: '',
        label: '',
        ticketAuto: true,
    })
}

const openCreate = () => {
    resetTransactionForm()
    transactionDialog.mode = 'create'
    transactionDialog.editId = ''
    transactionDialog.visible = true
}

const openEdit = (row: Transaction) => {
    Object.assign(transactionForm, {
        time: row.createdTime,
        timeMode: 'Manual',
        category: toNumber(row.categoryId) || 1,
        type: toNumber(row.typeId) || 1,
        username: row.username,
        remark: row.remark,
        amount: row.amount,
        bank: row.bankId || banks.value.find((bank) => bank.name === row.bank)?.id || '',
        label: row.labelId ? toNumber(row.labelId) : '',
        ticketAuto: row.ticket.length > 0,
    })
    transactionDialog.mode = 'edit'
    transactionDialog.editId = row.id
    transactionDialog.visible = true
}

const transactionTimestamp = () => {
    if (transactionForm.timeMode === 'Auto' || !transactionForm.time) {
        return Math.floor(Date.now() / 1000)
    }

    const date = new Date(transactionForm.time.replace(' ', 'T'))
    const timestamp = Math.floor(date.getTime() / 1000)
    return Number.isFinite(timestamp) ? timestamp : Math.floor(Date.now() / 1000)
}

const buildTransactPayload = (): DashboardTransactPayload => ({
    create_time: transactionTimestamp(),
    category: transactionForm.category,
    type: transactionForm.type,
    user_name: transactionForm.username,
    memo: transactionForm.remark,
    money: transactionForm.amount,
    bank_id: transactionForm.bank,
    label: transactionForm.label,
    game_ticket: transactionForm.ticketAuto ? 1 : 0,
})

const submitTransaction = () => {
    transactionDialog.loading = true
    const request =
        transactionDialog.mode === 'edit' && transactionDialog.editId !== ''
            ? editTransact({ ...buildTransactPayload(), id: transactionDialog.editId })
            : newTransact(buildTransactPayload())

    request
        .then(() => {
            transactionDialog.visible = false
            transactionPage.currentPage = 1
            return loadDashboard(1)
        })
        .finally(() => {
            transactionDialog.loading = false
        })
}

const mapHistory = (history: Record<string, unknown>): HistoryRow => ({
    id: (history.id || history.money_log_id || '') as number | string,
    editedBy: String(history.admin_name || ''),
    editedTime: formatDateTime(history.create_time),
    bankBefore: String(history.bank_befter ?? ''),
    bankAfter: String(history.bank_after ?? ''),
})

const historyChangeText = (row: HistoryRow) => t('dashboard.Bank change', { before: row.bankBefore, after: row.bankAfter })

const openHistory = (row: Transaction) => {
    historyDialog.visible = true
    historyDialog.loading = true
    historyDialog.rows = []

    logHistory({ id: row.id })
        .then((res) => {
            const data = Array.isArray(res.data) ? res.data : res.data?.list
            historyDialog.rows = Array.isArray(data) ? data.map((item) => mapHistory(item as Record<string, unknown>)) : []
        })
        .finally(() => {
            historyDialog.loading = false
        })
}

const openTransfer = (bank: Bank) => {
    Object.assign(transferForm, { bankFrom: bank.id, fromName: bank.name, bankTo: '', money: 0, remark: '' })
    transferDialog.visible = true
}

const submitBankTransfer = () => {
    transferDialog.loading = true
    bankTransact({
        money: transferForm.money,
        bank_from: transferForm.bankFrom,
        bank_to: transferForm.bankTo,
        remark: transferForm.remark,
    })
        .then(() => {
            transferDialog.visible = false
            return loadDashboard()
        })
        .finally(() => {
            transferDialog.loading = false
        })
}

const removeTransaction = (row: Transaction) => {
    delTransact({ id: row.id }).then(() => {
        return loadDashboard(transactionPage.currentPage)
    })
}

const setToday = () => {
    filters.startDate = today()
    filters.endDate = today()
    transactionPage.currentPage = 1
    loadDashboard(1).catch(() => {
        // Request errors are displayed by the shared Axios interceptor.
    })
}

const search = () => {
    transactionPage.currentPage = 1
    loadDashboard(1).catch(() => {
        // Request errors are displayed by the shared Axios interceptor.
    })
}

const onTransactionPageChange = (page: number) => {
    loadDashboard(page).catch(() => {
        // Request errors are displayed by the shared Axios interceptor.
    })
}

const transactionRowClass = ({ row }: { row: Transaction }) => (row.flow === 'in' ? 'transaction-in' : 'transaction-out')

onMounted(() => {
    loadDashboard().catch(() => {
        // Request errors are displayed by the shared Axios interceptor.
    })
})
</script>

<style scoped lang="scss">
.bookkeeping-dashboard {
    color: var(--el-text-color-primary);
    font-size: 13px;
    font-variant-numeric: tabular-nums;
}
.dashboard-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 310px;
    gap: var(--ba-main-space);
}
.dashboard-panel,
.transaction-section {
    border: 1px solid var(--ba-border-color-soft);
    border-radius: var(--ba-radius-panel);
    background: var(--ba-bg-color-overlay);
    box-shadow: var(--ba-shadow-card);
    overflow: hidden;
}
.panel-title {
    padding: 13px 16px;
    border-bottom: 1px solid var(--ba-border-color-soft);
    background: var(--ba-bg-color-soft);
    color: var(--el-text-color-primary);
    font-size: 15px;
    font-weight: 700;
    line-height: 1.4;
}
.table-scroll {
    overflow-x: auto;
}
.bank-table {
    width: 100%;
    border-collapse: collapse;
    th,
    td {
        padding: 11px 14px;
        border-bottom: 1px solid var(--ba-border-color-soft);
        text-align: left;
        vertical-align: middle;
    }
    th {
        color: var(--el-text-color-secondary);
        font-size: 12px;
        font-weight: 700;
        background: var(--ba-bg-color-soft);
        white-space: nowrap;
    }
    tbody tr {
        transition: background-color 0.18s ease;
    }
    tbody tr:hover:not(.bank-colored) {
        background: var(--el-color-primary-light-9);
    }
    tbody tr.bank-colored {
        color: var(--bank-row-text-color);
        text-shadow: none;

        td {
            border-bottom-color: var(--bank-row-border-color);
        }

        small {
            color: var(--bank-row-muted-color);
        }

        .balance {
            color: inherit;
        }

        :deep(.el-button) {
            --el-button-text-color: var(--bank-row-text-color);
            --el-button-bg-color: var(--bank-row-control-bg);
            --el-button-border-color: var(--bank-row-border-color);
            --el-button-hover-text-color: var(--bank-row-text-color);
            --el-button-hover-bg-color: var(--bank-row-control-hover-bg);
            --el-button-hover-border-color: var(--bank-row-border-color);
            --el-button-active-text-color: var(--bank-row-text-color);
            --el-button-active-bg-color: var(--bank-row-control-hover-bg);
            --el-button-active-border-color: var(--bank-row-border-color);
        }

        .calculator-button {
            color: var(--bank-row-text-color);
            border-color: var(--bank-row-border-color);
            background: var(--bank-row-control-bg);
            &:hover,
            &:focus-visible {
                background: var(--bank-row-control-hover-bg);
            }
        }

        :deep(.el-tag) {
            color: var(--bank-row-text-color);
            border-color: var(--bank-row-border-color);
            background: var(--bank-row-control-bg);
        }
    }
    strong,
    small {
        display: block;
    }
    small {
        margin-top: 3px;
        color: var(--el-text-color-secondary);
    }
    .balance {
        color: var(--el-color-primary);
        font-weight: 700;
        white-space: nowrap;
    }
    .empty-banks {
        padding: 24px;
        color: var(--el-text-color-secondary);
        text-align: center;
    }
}
.bank-muted {
    background: var(--el-fill-color-lighter);
}
.bank-operate {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
    :deep(.el-button.is-circle) {
        width: 30px;
        height: 30px;
    }
}
.bank-operate-main {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
}
.calculator-toggle {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
}
.calculator-toggle:not(:checked) ~ .bank-calculator {
    display: none;
}
.calculator-toggle:checked + .bank-operate-main .calculator-button {
    border-color: var(--el-color-primary);
    background: var(--el-color-primary-light-9);
    color: var(--el-color-primary);
}
.calculator-toggle:focus-visible + .bank-operate-main .calculator-button {
    outline: 2px solid var(--el-color-primary-light-5);
    outline-offset: 2px;
}
.calculator-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    padding: 0;
    border: 1px solid var(--el-border-color);
    border-radius: 50%;
    background: var(--el-bg-color);
    color: var(--el-text-color-regular);
    cursor: pointer;
    line-height: 1;
    transition:
        background-color 0.18s ease,
        border-color 0.18s ease,
        color 0.18s ease;
    &:hover,
    &:focus-visible {
        border-color: var(--el-color-primary);
        color: var(--el-color-primary);
        background: var(--el-color-primary-light-9);
        outline: none;
    }
}
.bank-calculator {
    width: min(300px, 100%);
    padding: 6px 8px 5px;
    border: 1px solid var(--ba-border-color-soft);
    border-radius: 2px;
    background: rgba(255, 255, 255, 0.94);
    box-shadow: 0 6px 14px rgba(15, 23, 42, 0.08);
    color: var(--el-text-color-primary);
}
.calculator-formula {
    display: flex;
    align-items: center;
    gap: 5px;
}
.calculator-input {
    flex: 1 1 125px;
    min-width: 112px;
    :deep(.el-input__wrapper) {
        min-height: 28px;
        border-radius: 0;
        box-shadow: 0 0 0 1px rgba(148, 163, 184, 0.72) inset;
    }
}
.calculator-equals {
    color: var(--el-text-color-primary);
    font-size: 15px;
    font-weight: 700;
    line-height: 1;
}
.calculator-result {
    min-width: 92px;
    color: var(--el-text-color-primary);
    font-size: 15px;
    font-weight: 700;
    line-height: 1;
    white-space: nowrap;
    &.is-invalid {
        color: var(--el-color-danger);
    }
}
.calculator-hint {
    margin-top: 3px;
    color: var(--el-text-color-regular);
    font-size: 11px;
    line-height: 1.2;
    span {
        margin-left: 4px;
        font-size: 12px;
        font-weight: 700;
        letter-spacing: 1px;
    }
}
.breakdown {
    display: inline-flex;
    flex-direction: column;
    gap: 4px;
    min-width: 118px;
    padding: 5px 8px;
    border: 1px solid rgba(148, 163, 184, 0.28);
    border-radius: 4px;
    background: rgba(248, 250, 252, 0.94);
    color: var(--el-text-color-regular);
    box-shadow: 0 1px 0 rgba(15, 23, 42, 0.04);
}
.breakdown-row {
    display: grid;
    grid-template-columns: 18px auto minmax(0, 1fr);
    align-items: center;
    gap: 4px;
    font-size: 12px;
    font-weight: 700;
    line-height: 1.15;
    white-space: nowrap;
}
.breakdown-label {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    border-radius: 3px;
    color: #ffffff;
    font-size: 11px;
    font-weight: 700;
}
.breakdown-count {
    color: var(--el-text-color-secondary);
    font-weight: 600;
}
.breakdown-in {
    color: var(--el-color-success);
    .breakdown-label {
        background: var(--el-color-success);
    }
}
.breakdown-out {
    color: var(--el-color-danger);
    .breakdown-label {
        background: var(--el-color-danger);
    }
}
.dot {
    font-style: normal;
    font-weight: 700;
}
.income,
.amount-in {
    color: var(--el-color-success);
}
.outcome,
.amount-out {
    color: var(--el-color-danger);
}
.more-info {
    display: block;
    width: 100%;
    padding: 11px;
    border: 0;
    border-top: 1px solid var(--ba-border-color-soft);
    background: var(--ba-bg-color-soft);
    color: var(--el-color-primary);
    cursor: pointer;
    font-weight: 700;
    transition: background-color 0.18s ease;
    &:hover {
        background: var(--el-color-primary-light-9);
    }
}
.summary-side {
    display: flex;
    flex-direction: column;
    gap: var(--ba-main-space);
}
.summary-panel dl {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 0;
    margin: 0;
}
.summary-panel dt,
.summary-panel dd {
    margin: 0;
    padding: 10px 14px;
    border-bottom: 1px solid var(--ba-border-color-soft);
}
.summary-panel dt {
    color: var(--el-text-color-secondary);
    font-weight: 600;
}
.summary-panel dd {
    color: var(--el-color-primary);
    font-weight: 700;
    text-align: right;
}
.create-button {
    width: 100%;
    min-height: 46px;
    font-weight: 700;
}
.webhook-alert {
    margin: var(--ba-main-space) 0;
    border: 1px solid rgba(183, 121, 31, 0.24);
    p {
        margin: 6px 0 0;
        line-height: 1.5;
    }
}
.filter-row {
    display: flex;
    justify-content: space-between;
    gap: 14px;
    padding: 14px 16px;
    border-bottom: 1px solid var(--ba-border-color-soft);
    background: var(--ba-bg-color-soft);
}
.date-filter,
.totals {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
}
.date-filter :deep(.el-date-editor) {
    width: 150px;
}
.date-filter label {
    color: var(--el-text-color-secondary);
    font-weight: 600;
}
.totals {
    justify-content: flex-end;
    color: var(--el-text-color-regular);
    b {
        font-weight: 700;
    }
    em {
        color: var(--el-color-primary);
        font-style: normal;
    }
}
.transaction-table :deep(.transaction-in) {
    --el-table-tr-bg-color: var(--el-color-success-light-9);
}
.transaction-table :deep(.transaction-out) {
    --el-table-tr-bg-color: var(--el-color-danger-light-9);
}
.pagination {
    display: flex;
    justify-content: flex-end;
    padding: 14px 16px;
    border-top: 1px solid var(--ba-border-color-soft);
    background: var(--ba-bg-color-soft);
}
.inline-mode {
    margin-left: 12px;
}
.dialog-note {
    margin: 0 0 8px;
    color: var(--el-text-color-secondary);
}
:deep(.el-dialog__body) {
    padding-top: 16px;
}
:deep(.el-form-item .el-select),
:deep(.el-form-item .el-input) {
    width: 100%;
}
@media screen and (max-width: 1100px) {
    .dashboard-grid {
        grid-template-columns: 1fr;
    }
}
@media screen and (max-width: 720px) {
    .filter-row {
        flex-direction: column;
    }
    .date-filter {
        align-items: stretch;
        label {
            width: 100%;
        }
        :deep(.el-date-editor),
        :deep(.el-button) {
            width: 100%;
        }
    }
    .totals {
        justify-content: flex-start;
    }
    .bank-table {
        min-width: 760px;
    }
    .pagination {
        justify-content: center;
    }
}
</style>
