<%@ page language="java" contentType="text/html; charset=utf-8"%>
<%@ page import="java.util.*" %>
<%@ page import="com.eactive.eai.rms.common.datasource.*" %>
<%@ page import="java.util.stream.Collectors" %>

<div class="dashboard-transactions">
    <div class="dashboard-header">
        <div class="header-title-container">
            <h2 class="section-title">거래처리 집계(일누적)</h2>
        </div>
    </div>
    <div class="card shadow mb-0" style="overflow-y:auto;">
        <div class="transaction-filters">
            <div class="filter-group">
                <button class="tran-filter-btn active" data-type="all">전체</button>
                <%
                    // serverTypeMap 변수를 가져오기
                    Map<String, List<DataSourceType>> serverTypeMap =
                            (Map<String, List<DataSourceType>>)request.getAttribute("serverTypeMap");

                    if (serverTypeMap == null) {
                        // application 스코프에서 가져오기 시도
                        serverTypeMap = (Map<String, List<DataSourceType>>)application.getAttribute("serverTypeMap");
                    }

                    Map<String, Integer> priorityMap = new HashMap<String, Integer>();
                    priorityMap.put("MCI", 0);
                    priorityMap.put("EAI", 1);
                    priorityMap.put("FEP", 2);
                    priorityMap.put("CGW", 3);
                    priorityMap.put("FGW", 4);
                    priorityMap.put("APIGW", 5);
                    priorityMap.put("BAP", 6);

                    Map<String,List<DataSourceType>> sortedMap = serverTypeMap.entrySet().stream()
                            .sorted(Comparator.comparingInt(e -> priorityMap.getOrDefault(e.getKey(), Integer.MAX_VALUE)))
                            .collect(Collectors.toMap(
                                    Map.Entry::getKey
                                    , Map.Entry::getValue
                                    ,(e1, e2) -> e1
                                    , LinkedHashMap::new
                            ));

                    if (sortedMap != null) {
                        // 서버 타입별 필터 버튼 생성
                        for (Map.Entry<String, List<DataSourceType>> entry : sortedMap.entrySet()) {
                            String serverType = entry.getKey();
                            List<DataSourceType> servers = entry.getValue();

                            // BAT 서버는 제외
                            if (DataSourceTypeManager.BAT.equals(serverType) || DataSourceTypeManager.BAP.equals(serverType)) {
                                continue;
                            }

                            String serverTypeText = servers.size() > 0 ? servers.get(0).getText() : serverType;

                            if( !serverTypeText.endsWith("GW") ) {
                %>
                <button class="tran-filter-btn" data-type="<%= serverType.toLowerCase() %>"><%= serverTypeText %></button>
                <% }
                }
                } %>
            </div>
        </div>
        <div class="transaction-table-container">
            <table class="transaction-table">
                <thead>
                <tr>
                    <th style="width: 1%"></th>
                    <th>업무그룹</th>
                    <th>정상처리</th>
                    <th>업무에러</th>
                    <th>타임아웃</th>
                    <th>통신에러</th>
                </tr>
                </thead>
                <tbody id="transaction-table-body">
                <!-- 거래 처리 데이터가 동적으로 추가됩니다 -->
                </tbody>
            </table>
        </div>
    </div>
</div>

<!-- 거래 처리 행 템플릿 -->
<template id="transaction-row-template">
    <tr>
        <td>
            <span class="instance-status status-normal"></span>
        </td>
        <td class="group-name">업무그룹</td>
        <td>
            <div class="metric">
                <div class="metric-value">
                    <span class="clickable transaction-count">0</span>
                    <span class="metric-change transaction-change" style="visibility: hidden;"><i class="bi bi-arrow-up-short"></i>0</span>
                </div>
            </div>
        </td>
        <td>
            <div class="metric">
                <div class="metric-value">
                    <span class="clickable error-count">0</span>
                    <span class="metric-change error-change" style="visibility: hidden;"><i class="bi bi-arrow-up-short"></i>0</span>
                </div>
            </div>
        </td>
        <td>
            <div class="metric">
                <div class="metric-value">
                    <span class="clickable timeout-count">0</span>
                    <span class="metric-change timeout-change" style="visibility: hidden;"><i class="bi bi-arrow-up-short"></i>0</span>
                </div>
            </div>
        </td>
        <td>
            <div class="metric">
                <div class="metric-value">
                    <span class="clickable syserror-count">0</span>
                    <span class="metric-change syserror-change" style="visibility: hidden;"><i class="bi bi-arrow-up-short"></i>0</span>
                </div>
            </div>
        </td>
    </tr>
</template>

<script>
    // 데이터 로딩 상태 플래그
    var isTransactionDataLoading = false;

    // 이전 데이터 저장 객체
    var previousTransactionData = {};

    // 숫자 형식화 함수 (천 단위 콤마 추가)
    function formatNumber(num) {
        return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
    }

    // 기존 행 업데이트 함수 수정
    function updateExistingRow(row, transactionData) {
        // 상태 업데이트
        var statusElement = row.querySelector('.instance-status');
        statusElement.className = 'instance-status';

        // 정상 처리와 오류 비율에 따라 색상 계산
        var totalCount = (transactionData.count || 0);
        var errorCount = (transactionData.error || 0) + (transactionData.timeout || 0) + (transactionData.syserror || 0);
        var totalTransactions = totalCount + errorCount;

        // 색상 설정
        if (totalTransactions > 0) {
            var successRatio = totalCount / totalTransactions;
            var statusColor = calculateStatusColor(successRatio);
            statusElement.style.backgroundColor = statusColor;
        } else {
            // 거래가 없는 경우 회색으로 표시
            statusElement.style.backgroundColor = '#9e9e9e';
        }

        // 이전 데이터 가져오기
        var prevData = previousTransactionData[transactionData.name] || {
            count: 0,
            error: 0,
            timeout: 0,
            syserror: 0
        };

        // 정상처리 건수 업데이트
        var transactionCount = row.querySelector('.transaction-count');
        transactionCount.textContent = formatNumber(transactionData.count || 0);

        // 증가량 표시
        var transactionChange = row.querySelector('.transaction-change');
        var countDiff = (transactionData.count || 0) - prevData.count;
        if (countDiff > 0) {
            transactionChange.innerHTML = '<i class="bi bi-arrow-up-short"></i>' + formatNumber(countDiff);
            transactionChange.style.visibility = 'visible';

            // 2초 후 사라지게 설정
            setTimeout(function() {
                transactionChange.style.visibility = 'hidden';
            }, 2000);
        } else {
            transactionChange.style.visibility = 'hidden';
        }

        // 업무에러 업데이트
        var errorCount = row.querySelector('.error-count');
        errorCount.textContent = formatNumber(transactionData.error || 0);

        // 증가량 표시
        var errorChange = row.querySelector('.error-change');
        var errorDiff = (transactionData.error || 0) - prevData.error;
        if (errorDiff > 0) {
            errorChange.innerHTML = '<i class="bi bi-arrow-up-short"></i>' + formatNumber(errorDiff);
            errorChange.style.visibility = 'visible';

            // 2초 후 사라지게 설정
            setTimeout(function() {
                errorChange.style.visibility = 'hidden';
            }, 2000);
        } else {
            errorChange.style.visibility = 'hidden';
        }

        // 타임아웃 업데이트
        var timeoutCount = row.querySelector('.timeout-count');
        timeoutCount.textContent = formatNumber(transactionData.timeout || 0);

        // 증가량 표시
        var timeoutChange = row.querySelector('.timeout-change');
        var timeoutDiff = (transactionData.timeout || 0) - prevData.timeout;
        if (timeoutDiff > 0) {
            timeoutChange.innerHTML = '<i class="bi bi-arrow-up-short"></i>' + formatNumber(timeoutDiff);
            timeoutChange.style.visibility = 'visible';

            // 2초 후 사라지게 설정
            setTimeout(function() {
                timeoutChange.style.visibility = 'hidden';
            }, 2000);
        } else {
            timeoutChange.style.visibility = 'hidden';
        }

        // 통신에러 업데이트
        var syserrorCount = row.querySelector('.syserror-count');
        syserrorCount.textContent = formatNumber(transactionData.syserror || 0);

        // 증가량 표시
        var syserrorChange = row.querySelector('.syserror-change');
        var syserrorDiff = (transactionData.syserror || 0) - prevData.syserror;
        if (syserrorDiff > 0) {
            syserrorChange.innerHTML = '<i class="bi bi-arrow-up-short"></i>' + formatNumber(syserrorDiff);
            syserrorChange.style.visibility = 'visible';

            // 2초 후 사라지게 설정
            setTimeout(function() {
                syserrorChange.style.visibility = 'hidden';
            }, 2000);
        } else {
            syserrorChange.style.visibility = 'hidden';
        }

        // 현재 데이터를 이전 데이터로 저장
        previousTransactionData[transactionData.name] = {
            count: transactionData.count || 0,
            error: transactionData.error || 0,
            timeout: transactionData.timeout || 0,
            syserror: transactionData.syserror || 0
        };
    }

    // 거래 행 생성 함수 수정
    function createTransactionRow(transactionData) {
        var template = document.getElementById('transaction-row-template');
        var clone = document.importNode(template.content, true);

        // 업무그룹 이름 설정
        clone.querySelector('.group-name').textContent = transactionData.name;

        // 정상 처리와 오류 비율에 따라 색상 계산
        var totalCount = (transactionData.count || 0);
        var errorCount = (transactionData.error || 0) + (transactionData.timeout || 0) + (transactionData.syserror || 0);
        var totalTransactions = totalCount + errorCount;

        // 상태 설정
        var statusElement = clone.querySelector('.instance-status');

        // 색상 설정
        if (totalTransactions > 0) {
            var successRatio = totalCount / totalTransactions;
            var statusColor = calculateStatusColor(successRatio);
            statusElement.style.backgroundColor = statusColor;
        } else {
            // 거래가 없는 경우 회색으로 표시
            statusElement.style.backgroundColor = '#9e9e9e';
        }

        // 정상처리 건수 설정
        clone.querySelector('.transaction-count').textContent = formatNumber(transactionData.count || 0);

        // 업무에러 설정
        clone.querySelector('.error-count').textContent = formatNumber(transactionData.error || 0);

        // 타임아웃 설정
        clone.querySelector('.timeout-count').textContent = formatNumber(transactionData.timeout || 0);

        // 통신에러 설정
        clone.querySelector('.syserror-count').textContent = formatNumber(transactionData.syserror || 0);

        // 현재 데이터를 이전 데이터로 저장
        previousTransactionData[transactionData.name] = {
            count: transactionData.count || 0,
            error: transactionData.error || 0,
            timeout: transactionData.timeout || 0,
            syserror: transactionData.syserror || 0
        };

        return clone;
    }

    // 거래 건수 테이블 업데이트 함수
    function updateTransactionTable(data) {
        if (!data || !data.transactions) return;

        var tableBody = document.getElementById('transaction-table-body');

        // 합계 값 초기화
        var totalCount = 0;
        var totalError = 0;
        var totalTimeout = 0;
        var totalSyserror = 0;

        // 현재 테이블에 있는 행들 저장
        var currentRows = {}; // 현재 행들을 저장할 객체

        // 현재 테이블의 상태를 저장
        Array.from(tableBody.querySelectorAll('tr:not(.total-row)')).forEach(function(row) {
            var transactionType = row.querySelector('.group-name').textContent;
            currentRows[transactionType] = row;
        });

        // 합계 행 제거 (나중에 다시 추가)
        var totalRow = tableBody.querySelector('.total-row');
        if (totalRow) {
            tableBody.removeChild(totalRow);
        }

        // 거래 데이터 행 업데이트 또는 추가
        data.transactions.forEach(function(transaction) {
            // TOTAL 항목은 표에 표시하지 않고 마지막에 별도로 처리
            // APIGW는 표시하고, CGW, FGW는 제외
            if (transaction.type === 'TOTAL' || (transaction.type.endsWith("GW") && transaction.type !== 'APIGW') ) {
                return;
            }

            // 각 거래별 데이터 설정
            var transactionData = {
                name: transaction.type,
                status: 'normal',
                count: transaction.success || 0,
                error: transaction.fail || 0,
                timeout: transaction.timeout || 0,
                syserror: transaction.syserror || 0
            };

            // 상태 설정: 에러가 많으면 경고 또는 오류 상태로 표시
            if ((transaction.fail + transaction.timeout + transaction.syserror) > 50) {
                transactionData.status = 'error';
            } else if ((transaction.fail + transaction.timeout + transaction.syserror) > 10) {
                transactionData.status = 'warning';
            }

            // 이미 존재하는 행인지 확인하여 업데이트 또는 새로 생성
            if (currentRows[transaction.type]) {
                updateExistingRow(currentRows[transaction.type], transactionData);
            } else {
                // 새 행 생성 및 추가
                var newRow = createTransactionRow(transactionData);
                tableBody.appendChild(newRow);
            }

            // 합계 계산
            totalCount += transactionData.count;
            totalError += transactionData.error;
            totalTimeout += transactionData.timeout;
            totalSyserror += transactionData.syserror;
        });

        // 사라진 행 제거 (현재 데이터에 없는 행)
        var remainingTypes = data.transactions
            .filter(t => t.type !== 'TOTAL')
            .map(t => t.type);

        for (var type in currentRows) {
            if (!remainingTypes.includes(type)) {
                tableBody.removeChild(currentRows[type]);
            }
        }

        // 합계 행 생성 및 추가
        totalRow = document.createElement('tr');
        totalRow.className = 'total-row';

        // 상태 아이콘 셀
        var statusCell = document.createElement('td');
        totalRow.appendChild(statusCell);

        // 업무그룹 셀
        var nameCell = document.createElement('td');
        nameCell.className = 'group-name';
        nameCell.textContent = '합계';
        totalRow.appendChild(nameCell);

        // 정상처리 셀
        var countCell = document.createElement('td');
        var countMetric = document.createElement('div');
        countMetric.className = 'metric';

        var countValue = document.createElement('div');
        countValue.className = 'metric-value';

        var countSpan = document.createElement('span');
        countSpan.className = 'transaction-count';
        countSpan.textContent = formatNumber(totalCount);

        // 가짜 metric-change span 추가 (정상처리)
        var countChangeSpan = document.createElement('span');
        countChangeSpan.className = 'metric-change transaction-change';
        countChangeSpan.style.visibility = 'hidden';
        countChangeSpan.innerHTML = '<i class="bi bi-arrow-up-short"></i>0';

        countValue.appendChild(countSpan);
        countValue.appendChild(countChangeSpan); // 가짜 span 추가
        countMetric.appendChild(countValue);
        countCell.appendChild(countMetric);
        totalRow.appendChild(countCell);

        // 업무에러 셀
        var errorCell = document.createElement('td');
        var errorMetric = document.createElement('div');
        errorMetric.className = 'metric';

        var errorValue = document.createElement('div');
        errorValue.className = 'metric-value';

        var errorSpan = document.createElement('span');
        errorSpan.className = 'error-count';
        errorSpan.textContent = formatNumber(totalError);

        // 가짜 metric-change span 추가 (업무에러)
        var errorChangeSpan = document.createElement('span');
        errorChangeSpan.className = 'metric-change error-change';
        errorChangeSpan.style.visibility = 'hidden';
        errorChangeSpan.innerHTML = '<i class="bi bi-arrow-up-short"></i>0';

        errorValue.appendChild(errorSpan);
        errorValue.appendChild(errorChangeSpan); // 가짜 span 추가
        errorMetric.appendChild(errorValue);
        errorCell.appendChild(errorMetric);
        totalRow.appendChild(errorCell);

        // 타임아웃 셀
        var timeoutCell = document.createElement('td');
        var timeoutMetric = document.createElement('div');
        timeoutMetric.className = 'metric';

        var timeoutValue = document.createElement('div');
        timeoutValue.className = 'metric-value';

        var timeoutSpan = document.createElement('span');
        timeoutSpan.className = 'timeout-count';
        timeoutSpan.textContent = formatNumber(totalTimeout);

        // 가짜 metric-change span 추가 (타임아웃)
        var timeoutChangeSpan = document.createElement('span');
        timeoutChangeSpan.className = 'metric-change timeout-change';
        timeoutChangeSpan.style.visibility = 'hidden';
        timeoutChangeSpan.innerHTML = '<i class="bi bi-arrow-up-short"></i>0';

        timeoutValue.appendChild(timeoutSpan);
        timeoutValue.appendChild(timeoutChangeSpan); // 가짜 span 추가
        timeoutMetric.appendChild(timeoutValue);
        timeoutCell.appendChild(timeoutMetric);
        totalRow.appendChild(timeoutCell);

        // 통신에러 셀
        var syserrorCell = document.createElement('td');
        var syserrorMetric = document.createElement('div');
        syserrorMetric.className = 'metric';

        var syserrorValue = document.createElement('div');
        syserrorValue.className = 'metric-value';

        var syserrorSpan = document.createElement('span');
        syserrorSpan.className = 'syserror-count';
        syserrorSpan.textContent = formatNumber(totalSyserror);

        // 가짜 metric-change span 추가 (통신에러)
        var syserrorChangeSpan = document.createElement('span');
        syserrorChangeSpan.className = 'metric-change syserror-change';
        syserrorChangeSpan.style.visibility = 'hidden';
        syserrorChangeSpan.innerHTML = '<i class="bi bi-arrow-up-short"></i>0';

        syserrorValue.appendChild(syserrorSpan);
        syserrorValue.appendChild(syserrorChangeSpan); // 가짜 span 추가
        syserrorMetric.appendChild(syserrorValue);
        syserrorCell.appendChild(syserrorMetric);
        totalRow.appendChild(syserrorCell);

        // 테이블에 합계 행 추가
        tableBody.appendChild(totalRow);
    }

    // 트랜잭션 데이터 로드 함수
    function loadTransactionData(type) {
        // 이미 로딩 중이면 중복 요청 방지
        if (isTransactionDataLoading) {
            return;
        }

        // 로딩 상태 플래그 설정
        isTransactionDataLoading = true;

        // 전역 로딩 이벤트 발생 (DashboardEventManager 사용)
        if (window.DashboardEventManager) {
            window.DashboardEventManager.trigger('loading-start');
        }

        // 필터 조건을 파라미터로 API 호출
        ModernDashboardApi.getTransactionInfo(type, function(data) {
            // 데이터 처리 완료 후 UI 업데이트
            // 테이블 업데이트
            updateTransactionTable(data);

            // 전역 로딩 완료 이벤트 발생
            if (window.DashboardEventManager) {
                window.DashboardEventManager.trigger('loading-end');
            }

            // 로딩 상태 플래그 해제
            isTransactionDataLoading = false;
        });
    }

    // 트랜잭션 필터 버튼 클릭 이벤트
    $('.tran-filter-btn').click(function() {
        // 모든 버튼 비활성화
        $('.tran-filter-btn').removeClass('active');

        // 클릭한 버튼 활성화
        $(this).addClass('active');

        // 선택한 타입에 따라 트랜잭션 데이터 필터링 로직 추가
        var type = $(this).data('type');
        loadTransactionData(type);
    });

    // 실제 서비스에서 표시할 거래 유형 목록 (정렬 순서 포함)
    var preferredTransactionOrder = ['MCI', 'EAI', 'FEP', 'MCU', 'APIGW'];

    // refreshDashboardData 함수가 호출될 때 거래 처리 테이블이 초기화되지 않도록
    // modern-dashboard.js 파일의 refreshDashboardData 함수를 확장합니다.
    $(document).ready(function() {
        // DashboardEventManager를 사용하여 새로고침 이벤트 구독
        if (window.DashboardEventManager) {
            window.DashboardEventManager.on('refresh', function() {
                // 트랜잭션 정보 조회 - 현재 선택된 필터 사용
                var activeType = $('.tran-filter-btn.active').data('type') || 'all';
                console.log('거래처리 집계 데이터 갱신 시작: ' + activeType);
                loadTransactionData(activeType);
            });

            // 초기화 완료 이벤트 로깅
            console.log('거래처리 집계 컴포넌트 초기화 완료');
        }

        // 페이지 로드 시 데이터 로드
        var activeType = $('.tran-filter-btn.active').data('type') || 'all';
        loadTransactionData(activeType);
    });

    // 성공 비율에 따른 색상 계산 함수
    function calculateStatusColor(successRatio) {
        // 성공 비율이 0.5(50%)일 때 주황색(#ff9800)
        // 성공 비율이 1.0(100%)에 가까울수록 초록색(#4caf50)
        // 성공 비율이 0.0(0%)에 가까울수록 빨간색(#e53935)

        // 정확히 50%에 가까울 때는 주황색
        if (Math.abs(successRatio - 0.5) < 0.05) {
            return '#ff9800'; // 주황색 (50:50 비율 근처)
        } else if (successRatio > 0.5) {
            // 50% ~ 100% 사이: 주황색에서 초록색으로 매우 급격한 변화
            // 55% 이상이면 거의 바로 초록색으로 변화
            var greenRatio;

            if (successRatio > 0.65) {
                // 65% 이상이면 완전한 초록색
                greenRatio = 1;
            } else {
                // 50%~65% 사이에서 급격하게 변화
                greenRatio = (successRatio - 0.5) * 6.67; // 0.5에서 0.65 사이를 0에서 1로 매핑
            }

            // 주황색(#ff9800)에서 초록색(#4caf50)으로 보간
            var r = Math.round(255 - (255 - 76) * greenRatio);
            var g = Math.round(152 + (175 - 152) * greenRatio);
            var b = Math.round(0 + (80 - 0) * greenRatio);

            return 'rgb(' + r + ',' + g + ',' + b + ')';
        } else {
            // 0% ~ 50% 사이: 빨간색에서 주황색으로 매우 급격한 변화
            // 45% 이하면 거의 바로 빨간색으로 변화
            var orangeRatio;

            if (successRatio < 0.35) {
                // 35% 이하면 완전한 빨간색
                orangeRatio = 0;
            } else {
                // 35%~50% 사이에서 급격하게 변화
                orangeRatio = (successRatio - 0.35) * 6.67; // 0.35에서 0.5 사이를 0에서 1로 매핑
            }

            // 빨간색(#e53935)에서 주황색(#ff9800)으로 보간
            var r = Math.round(229 + (255 - 229) * orangeRatio);
            var g = Math.round(57 + (152 - 57) * orangeRatio);
            var b = Math.round(53 + (0 - 53) * orangeRatio);

            return 'rgb(' + r + ',' + g + ',' + b + ')';
        }
    }
</script>

<style>
    /* 트랜잭션 섹션 */
    .dashboard-transactions .section-title {
        font-size: 1.1rem;
        font-weight: 600;
        margin-bottom: 0;
        padding-bottom: 0;
        border-bottom: none;
        flex-shrink: 0;
    }

    .dashboard-transactions .card {
        border-radius: 0.35rem;
        box-shadow: 0 0.15rem 1.75rem 0 rgba(58, 59, 69, 0.15);
        /* overflow: hidden; */ /* 스크롤바 제거를 위해 제거 */
        /* height: 242px; */ /* 스크롤바 제거를 위해 제거 */
    }

    .transaction-filters {
        display: flex;
        justify-content: flex-start;
        align-items: center;
        padding: 0.75rem 1rem;
        border-bottom: 1px solid #e3e6f0;
    }

    .filter-group {
        display: flex;
        flex-wrap: wrap;
        gap: 0.5rem;
    }

    .filter-btn:hover {
        background-color: #e9ecef;
        color: #495057;
    }

    .filter-btn.active {
        background-color: var(--color-primary);
        color: white;
        border-color: var(--color-primary);
    }

    .transaction-table-container {
        /* max-height: 300px; */ /* 스크롤바 제거를 위해 제거 */
        /* overflow-y: auto; */ /* 스크롤바 제거 */
        position: relative;
    }

    .transaction-table {
        width: 100%;
        border-collapse: collapse;
        font-size: 0.85rem;
        table-layout: fixed;
    }

    .transaction-table th {
        background-color: #f8f9fc;
        font-weight: 600;
        text-align: center;
        padding: 0.75rem 1rem;
        border-bottom: 1px solid #e3e6f0;
        position: sticky;
        top: 0;
        z-index: 10;
    }

    .transaction-table td {
        padding: 0.75rem 1rem;
        border-bottom: 1px solid #f0f0f0;
        vertical-align: middle;
    }

    .transaction-table td:nth-child(1) {
        text-align: left;
    }

    .transaction-table td:nth-child(2) {
        text-align: center;
    }

    .transaction-table td:nth-child(n+3) {
        text-align: center;
    }

    .transaction-table tr:last-child td {
        border-bottom: none;
    }

    .transaction-table tr:hover {
        background-color: rgba(0, 0, 0, 0.02);
    }

    .transaction-table tr.total-row {
        background-color: rgba(200, 200, 200, 0.2);
        font-weight: 600;
    }

    .transaction-table tr.total-row td {
        border-bottom: 2px solid #9e9e9e;
    }

    .transaction-table tr.total-row .group-name {
        color: #616161;
    }

    /* 인스턴스 상태 표시 */
    .instance-status {
        display: inline-block;
        width: 10px;
        height: 10px;
        border-radius: 50%;
        margin-right: 5px;
    }

    .status-normal {
        background-color: #4caf50;
    }

    .status-warning {
        background-color: #ff9800;
    }

    .status-error {
        background-color: #e53935;
    }

    /* 메트릭 스타일 */
    .metric {
        display: flex;
        flex-direction: column;
        position: relative;
        min-height: 24px;
    }

    .metric-value {
        display: flex;
        align-items: center;
        justify-content: center;
        position: relative;
    }

    .clickable {
        cursor: pointer;
        font-weight: 500;
    }

    .transaction-count {
        color: #4caf50;
        font-weight: 600;
    }

    .error-count {
        color: #e53935;
        font-weight: 600;
    }

    .timeout-count {
        color: #ff9800;
        font-weight: 600;
    }

    .syserror-count {
        color: #e53935;
        font-weight: 600;
    }

    .metric-change {
        font-size: 0.75rem;
        color: #4caf50;
        font-weight: 500;
        display: inline-flex;
        align-items: center;
        transition: opacity 0.3s ease;
        position: relative;
        margin-left: 2px;
        white-space: nowrap;
    }

    .error-change {
        color: #e53935;
    }

    .timeout-change {
        color: #ff9800;
    }

    .syserror-change {
        color: #e53935;
    }

    .metric-change i {
        font-size: 1rem;
        margin-right: 0;
    }

    /* 그룹 이름 스타일 */
    .group-name {
        text-align: center;
    }

    /* 대시보드 헤더 스타일 */
    .dashboard-header {
        display: flex;
        justify-content: space-between;
        align-items: center;
        margin-bottom: 0.5rem;
    }

    /* 제목과 버튼을 한 줄에 나란히 표시하기 위한 컨테이너 */
    .header-title-container {
        display: flex;
        align-items: center;
    }

    /* 트랜지션 효과 제거 */
    #transaction-table-body {
        /* transition: opacity 0.2s ease; */
    }
</style>
