#!/usr/bin/env node

/**
 * Drama Ling 元件驗證工具
 * 功能：驗證HTML元件是否符合設計規範
 * 作者：Drama Ling 開發團隊
 * 日期：2025-09-15
 */

const fs = require('fs');
const path = require('path');

// ANSI 顏色碼
const colors = {
    red: '\x1b[31m',
    green: '\x1b[32m',
    yellow: '\x1b[33m',
    reset: '\x1b[0m'
};

// 設計規範定義
const DESIGN_SPECS = {
    // 必須使用的CSS類別前綴
    classPrefixes: ['btn-', 'card-', 'input-', 'alert-', 'badge-', 'modal-'],

    // 必須包含的屬性
    requiredAttributes: {
        'button': ['type', 'class'],
        'input': ['type', 'id', 'name'],
        'img': ['alt', 'src'],
        'a': ['href']
    },

    // 顏色變數
    colorVariables: [
        '--primary', '--primary-dark', '--primary-light',
        '--secondary', '--secondary-dark', '--secondary-light',
        '--success', '--warning', '--danger', '--info',
        '--gray-50', '--gray-100', '--gray-200', '--gray-300',
        '--gray-400', '--gray-500', '--gray-600', '--gray-700',
        '--gray-800', '--gray-900'
    ],

    // 間距變數
    spacingVariables: [
        '--space-1', '--space-2', '--space-3', '--space-4',
        '--space-5', '--space-6', '--space-8', '--space-10'
    ]
};

class ComponentValidator {
    constructor() {
        this.errors = [];
        this.warnings = [];
        this.passed = 0;
        this.failed = 0;
    }

    // 日誌方法
    logError(file, message) {
        this.errors.push({ file, message });
        console.log(`${colors.red}[ERROR]${colors.reset} ${file}: ${message}`);
    }

    logWarning(file, message) {
        this.warnings.push({ file, message });
        console.log(`${colors.yellow}[WARNING]${colors.reset} ${file}: ${message}`);
    }

    logSuccess(message) {
        console.log(`${colors.green}[✓]${colors.reset} ${message}`);
    }

    // 驗證HTML文件
    validateHTMLFile(filePath) {
        const fileName = path.basename(filePath);
        console.log(`\n檢查文件: ${fileName}`);

        try {
            const content = fs.readFileSync(filePath, 'utf8');

            // 檢查基本結構
            this.checkHTMLStructure(fileName, content);

            // 檢查必要屬性
            this.checkRequiredAttributes(fileName, content);

            // 檢查CSS類別命名
            this.checkCSSClasses(fileName, content);

            // 檢查無障礙性
            this.checkAccessibility(fileName, content);

            // 檢查響應式設計
            this.checkResponsive(fileName, content);

            this.passed++;
            this.logSuccess(`${fileName} 驗證通過`);

        } catch (error) {
            this.failed++;
            this.logError(fileName, `無法讀取文件: ${error.message}`);
        }
    }

    // 檢查HTML基本結構
    checkHTMLStructure(file, content) {
        // 檢查DOCTYPE
        if (!content.includes('<!DOCTYPE html>')) {
            this.logWarning(file, '缺少 <!DOCTYPE html> 聲明');
        }

        // 檢查meta viewport
        if (!content.includes('viewport')) {
            this.logError(file, '缺少 viewport meta 標籤（響應式設計必需）');
        }

        // 檢查字符編碼
        if (!content.includes('charset="UTF-8"') && !content.includes('charset=UTF-8')) {
            this.logError(file, '缺少 UTF-8 字符編碼聲明');
        }
    }

    // 檢查必要屬性
    checkRequiredAttributes(file, content) {
        for (const [element, attributes] of Object.entries(DESIGN_SPECS.requiredAttributes)) {
            const regex = new RegExp(`<${element}[^>]*>`, 'gi');
            const matches = content.match(regex) || [];

            matches.forEach(match => {
                attributes.forEach(attr => {
                    if (!match.includes(attr)) {
                        this.logWarning(file, `<${element}> 元素缺少 ${attr} 屬性`);
                    }
                });
            });
        }
    }

    // 檢查CSS類別命名規範
    checkCSSClasses(file, content) {
        const classRegex = /class="([^"]*)"/g;
        let match;

        while ((match = classRegex.exec(content)) !== null) {
            const classes = match[1].split(' ');

            classes.forEach(className => {
                // 檢查是否使用 BEM 命名或設計系統前綴
                const isValidClass =
                    DESIGN_SPECS.classPrefixes.some(prefix => className.startsWith(prefix)) ||
                    className.includes('__') || // BEM element
                    className.includes('--');    // BEM modifier

                if (!isValidClass && className && !className.startsWith('library-') && !className.startsWith('showcase-')) {
                    this.logWarning(file, `CSS類別 "${className}" 可能不符合命名規範`);
                }
            });
        }
    }

    // 檢查無障礙性
    checkAccessibility(file, content) {
        // 檢查圖片alt屬性
        const imgRegex = /<img[^>]*>/g;
        let match;

        while ((match = imgRegex.exec(content)) !== null) {
            if (!match[0].includes('alt=')) {
                this.logError(file, '圖片缺少 alt 屬性（無障礙性要求）');
            }
        }

        // 檢查表單標籤
        const inputRegex = /<input[^>]*>/g;
        const inputs = content.match(inputRegex) || [];

        inputs.forEach(input => {
            if (!input.includes('type="hidden"') && !input.includes('aria-label')) {
                // 檢查是否有對應的label
                const idMatch = input.match(/id="([^"]*)"/);
                if (idMatch) {
                    const hasLabel = content.includes(`for="${idMatch[1]}"`);
                    if (!hasLabel) {
                        this.logWarning(file, `輸入框缺少對應的 <label> 標籤`);
                    }
                }
            }
        });

        // 檢查ARIA屬性
        if (content.includes('role="button"') && !content.includes('tabindex')) {
            this.logWarning(file, '具有 role="button" 的元素應該包含 tabindex 屬性');
        }
    }

    // 檢查響應式設計
    checkResponsive(file, content) {
        // 檢查是否使用響應式單位
        const hasResponsiveUnits =
            content.includes('rem') ||
            content.includes('em') ||
            content.includes('%') ||
            content.includes('vw') ||
            content.includes('vh');

        if (!hasResponsiveUnits) {
            this.logWarning(file, '未檢測到響應式單位（rem, em, %, vw, vh）');
        }

        // 檢查媒體查詢
        if (!content.includes('@media')) {
            this.logWarning(file, '未檢測到媒體查詢（響應式設計）');
        }
    }

    // 驗證CSS文件
    validateCSSFile(filePath) {
        const fileName = path.basename(filePath);
        console.log(`\n檢查CSS文件: ${fileName}`);

        try {
            const content = fs.readFileSync(filePath, 'utf8');

            // 檢查設計代幣使用
            this.checkDesignTokens(fileName, content);

            // 檢查顏色變數
            this.checkColorVariables(fileName, content);

            // 檢查間距變數
            this.checkSpacingVariables(fileName, content);

            this.passed++;
            this.logSuccess(`${fileName} CSS驗證通過`);

        } catch (error) {
            this.failed++;
            this.logError(fileName, `無法讀取CSS文件: ${error.message}`);
        }
    }

    // 檢查設計代幣
    checkDesignTokens(file, content) {
        // 檢查是否使用CSS變數而非硬編碼值
        const hardcodedColors = content.match(/#[0-9a-fA-F]{3,6}/g) || [];

        if (hardcodedColors.length > 5) {
            this.logWarning(file, `發現 ${hardcodedColors.length} 個硬編碼顏色值，建議使用CSS變數`);
        }

        // 檢查硬編碼的間距
        const hardcodedSpacing = content.match(/margin:\s*\d+px|padding:\s*\d+px/g) || [];

        if (hardcodedSpacing.length > 10) {
            this.logWarning(file, `發現 ${hardcodedSpacing.length} 個硬編碼間距值，建議使用間距變數`);
        }
    }

    // 檢查顏色變數
    checkColorVariables(file, content) {
        const unusedColors = DESIGN_SPECS.colorVariables.filter(
            color => !content.includes(color)
        );

        if (unusedColors.length > 0 && unusedColors.length < DESIGN_SPECS.colorVariables.length / 2) {
            this.logWarning(file, `未使用的顏色變數: ${unusedColors.slice(0, 5).join(', ')}...`);
        }
    }

    // 檢查間距變數
    checkSpacingVariables(file, content) {
        const hasSpacingVars = DESIGN_SPECS.spacingVariables.some(
            spacing => content.includes(spacing)
        );

        if (!hasSpacingVars) {
            this.logWarning(file, '未使用間距變數，建議使用統一的間距系統');
        }
    }

    // 生成報告
    generateReport() {
        const reportPath = path.join(__dirname, '../VALIDATION_REPORT.md');
        const timestamp = new Date().toISOString().replace('T', ' ').substr(0, 19);

        let report = `# 元件驗證報告\n\n`;
        report += `**生成時間**: ${timestamp}\n\n`;
        report += `## 📊 驗證統計\n\n`;
        report += `- ✅ 通過: ${this.passed} 個文件\n`;
        report += `- ❌ 失敗: ${this.failed} 個文件\n`;
        report += `- ⚠️ 警告: ${this.warnings.length} 個\n`;
        report += `- 🚨 錯誤: ${this.errors.length} 個\n\n`;

        if (this.errors.length > 0) {
            report += `## 🚨 錯誤列表\n\n`;
            this.errors.forEach(({ file, message }) => {
                report += `- **${file}**: ${message}\n`;
            });
            report += '\n';
        }

        if (this.warnings.length > 0) {
            report += `## ⚠️ 警告列表\n\n`;
            this.warnings.forEach(({ file, message }) => {
                report += `- **${file}**: ${message}\n`;
            });
            report += '\n';
        }

        report += `## 📝 建議\n\n`;
        report += `1. 修復所有錯誤以確保符合設計規範\n`;
        report += `2. 檢查警告並根據需要進行調整\n`;
        report += `3. 使用設計代幣取代硬編碼值\n`;
        report += `4. 確保所有元件都有適當的無障礙性支援\n`;

        fs.writeFileSync(reportPath, report);
        console.log(`\n📋 驗證報告已生成: ${reportPath}`);
    }

    // 執行驗證
    run() {
        console.log('=====================================');
        console.log('Drama Ling 元件驗證工具');
        console.log('=====================================\n');

        const componentLibraryPath = path.join(__dirname, '../../component-library');

        // 驗證HTML文件
        this.validateDirectory(componentLibraryPath, '.html', this.validateHTMLFile.bind(this));

        // 驗證CSS文件
        const cssPath = path.join(componentLibraryPath, 'assets/styles');
        this.validateDirectory(cssPath, '.css', this.validateCSSFile.bind(this));

        // 生成報告
        this.generateReport();

        console.log('\n=====================================');
        console.log('驗證完成！');
        console.log('=====================================');

        // 返回退出碼
        process.exit(this.errors.length > 0 ? 1 : 0);
    }

    // 驗證目錄中的文件
    validateDirectory(dirPath, extension, validateFunc) {
        if (!fs.existsSync(dirPath)) {
            this.logError('系統', `目錄不存在: ${dirPath}`);
            return;
        }

        const files = this.getAllFiles(dirPath, extension);
        files.forEach(file => validateFunc(file));
    }

    // 遞歸獲取所有文件
    getAllFiles(dirPath, extension) {
        let files = [];

        const items = fs.readdirSync(dirPath);

        items.forEach(item => {
            const fullPath = path.join(dirPath, item);
            const stat = fs.statSync(fullPath);

            if (stat.isDirectory()) {
                files = files.concat(this.getAllFiles(fullPath, extension));
            } else if (path.extname(fullPath) === extension) {
                files.push(fullPath);
            }
        });

        return files;
    }
}

// 執行驗證
const validator = new ComponentValidator();
validator.run();