"""
在线打字练习网站 - 完整应用
这是一个使用Flask构建的在线打字练习网站，包含完整的后端和前端代码。
运行方法：
1. 安装依赖：pip install flask
2. 运行：python typing_practice_app.py
3. 访问：http://localhost:5000
"""

from flask import Flask, render_template_string, jsonify, request
import random
import os

app = Flask(__name__)

# ==================== 练习文本库 ====================
practice_texts = [
    {
        "title": "科技",
        "text": "Python是一种解释型、面向对象、动态数据类型的高级程序设计语言。"
    },
    {
        "title": "生活",
        "text": "保持积极乐观的心态，让生活充满阳光和希望。"
    },
    {
        "title": "名言",
        "text": "千里之行，始于足下。不积跬步，无以至千里。"
    },
    {
        "title": "编程",
        "text": "在计算机科学中，算法是解决问题的一系列清晰指令。"
    },
    {
        "title": "英语",
        "text": "The quick brown fox jumps over the lazy dog near the river bank."
    },
    {
        "title": "古诗",
        "text": "床前明月光，疑是地上霜。举头望明月，低头思故乡。"
    },
    {
        "title": "励志",
        "text": "世上无难事，只要肯登攀。一分耕耘，一分收获。"
    },
    {
        "title": "散文",
        "text": "春天来了，万物复苏，小草偷偷地从土里钻出来，嫩嫩的，绿绿的。"
    },
    {
        "title": "英文名言",
        "text": "To be or not to be, that is a question. Whether tis nobler in the mind to suffer."
    }
]

# ==================== HTML模板 ====================
HTML_TEMPLATE = '''
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>⌨️ 在线打字练习 - 提升你的打字速度</title>
    <style>
        /* ==================== 全局样式 ==================== */
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        :root {
            --primary-color: #667eea;
            --secondary-color: #764ba2;
            --success-color: #28a745;
            --danger-color: #dc3545;
            --warning-color: #ffc107;
            --info-color: #17a2b8;
            --dark-color: #343a40;
            --light-color: #f8f9fa;
            --gradient: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background: var(--gradient);
            min-height: 100vh;
            padding: 20px;
            line-height: 1.6;
        }

        .container {
            max-width: 900px;
            margin: 0 auto;
            background: white;
            border-radius: 20px;
            padding: 40px;
            box-shadow: 0 20px 60px rgba(0,0,0,0.3);
            animation: slideIn 0.5s ease-out;
        }

        @keyframes slideIn {
            from {
                opacity: 0;
                transform: translateY(-20px);
            }
            to {
                opacity: 1;
                transform: translateY(0);
            }
        }

        /* ==================== 头部样式 ==================== */
        header {
            text-align: center;
            margin-bottom: 40px;
        }

        h1 {
            color: var(--dark-color);
            font-size: 2.8em;
            margin-bottom: 10px;
            text-shadow: 2px 2px 4px rgba(0,0,0,0.1);
        }

        .subtitle {
            color: #6c757d;
            font-size: 1.2em;
        }

        /* ==================== 统计卡片 ==================== */
        .stats-container {
            display: grid;
            grid-template-columns: repeat(3, 1fr);
            gap: 20px;
            margin-bottom: 30px;
        }

        .stat-card {
            background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
            border-radius: 15px;
            padding: 20px;
            display: flex;
            align-items: center;
            transition: transform 0.3s, box-shadow 0.3s;
            box-shadow: 0 4px 6px rgba(0,0,0,0.1);
        }

        .stat-card:hover {
            transform: translateY(-5px);
            box-shadow: 0 8px 15px rgba(0,0,0,0.2);
        }

        .stat-icon {
            font-size: 2.5em;
            margin-right: 15px;
        }

        .stat-info {
            flex: 1;
        }

        .stat-label {
            display: block;
            color: #6c757d;
            font-size: 0.9em;
            margin-bottom: 5px;
            text-transform: uppercase;
            letter-spacing: 1px;
        }

        .stat-value {
            display: block;
            color: var(--dark-color);
            font-size: 2em;
            font-weight: bold;
        }

        /* ==================== 进度条部分 ==================== */
        .progress-section {
            margin-bottom: 20px;
        }

        .progress-header {
            display: flex;
            justify-content: space-between;
            margin-bottom: 10px;
            color: #6c757d;
        }

        .text-title {
            font-weight: bold;
            color: var(--primary-color);
        }

        .char-count {
            background: var(--light-color);
            padding: 3px 10px;
            border-radius: 15px;
            font-size: 0.9em;
        }

        .progress-bar-container {
            width: 100%;
            height: 25px;
            background-color: #e9ecef;
            border-radius: 15px;
            overflow: hidden;
            box-shadow: inset 0 1px 3px rgba(0,0,0,0.2);
        }

        .progress-bar {
            height: 100%;
            background: var(--gradient);
            width: 0%;
            transition: width 0.3s ease;
            border-radius: 15px;
            position: relative;
            overflow: hidden;
        }

        .progress-bar::after {
            content: '';
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background: linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent);
            animation: shimmer 2s infinite;
        }

        @keyframes shimmer {
            0% { transform: translateX(-100%); }
            100% { transform: translateX(100%); }
        }

        /* ==================== 文本显示区域 ==================== */
        .text-display {
            background: var(--light-color);
            border: 3px solid #dee2e6;
            border-radius: 15px;
            padding: 25px;
            margin-bottom: 20px;
            min-height: 150px;
            font-size: 1.3em;
            line-height: 1.8;
            box-shadow: inset 0 2px 4px rgba(0,0,0,0.05);
        }

        .target-text {
            word-break: break-word;
        }

        .char {
            display: inline-block;
            transition: all 0.2s;
        }

        .correct-char {
            color: var(--success-color);
            background-color: #d4edda;
            border-radius: 3px;
            animation: correctPulse 0.3s;
        }

        .incorrect-char {
            color: var(--danger-color);
            background-color: #f8d7da;
            border-radius: 3px;
            text-decoration: underline wavy var(--danger-color);
        }

        .current-char {
            background-color: #fff3cd;
            border-bottom: 3px solid var(--warning-color);
            animation: blink 1s infinite;
        }

        @keyframes correctPulse {
            0% { transform: scale(1); }
            50% { transform: scale(1.1); }
            100% { transform: scale(1); }
        }

        @keyframes blink {
            0%, 100% { opacity: 1; }
            50% { opacity: 0.5; }
        }

        /* ==================== 输入区域 ==================== */
        .input-area {
            margin-bottom: 25px;
        }

        .input-label {
            display: block;
            margin-bottom: 8px;
            color: var(--dark-color);
            font-weight: bold;
        }

        textarea {
            width: 100%;
            padding: 15px;
            font-size: 1.2em;
            border: 3px solid #dee2e6;
            border-radius: 15px;
            resize: vertical;
            font-family: inherit;
            transition: all 0.3s;
            background: white;
        }

        textarea:focus {
            outline: none;
            border-color: var(--primary-color);
            box-shadow: 0 0 0 4px rgba(102, 126, 234, 0.1);
            transform: scale(1.01);
        }

        textarea::placeholder {
            color: #adb5bd;
            font-style: italic;
        }

        /* ==================== 控制按钮 ==================== */
        .controls {
            display: grid;
            grid-template-columns: repeat(3, 1fr);
            gap: 15px;
            margin-bottom: 30px;
        }

        .btn {
            padding: 15px 20px;
            font-size: 1.1em;
            border: none;
            border-radius: 10px;
            cursor: pointer;
            transition: all 0.3s;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 8px;
            font-weight: 600;
            text-transform: uppercase;
            letter-spacing: 0.5px;
        }

        .btn:hover {
            transform: translateY(-3px);
            box-shadow: 0 10px 20px rgba(0,0,0,0.2);
        }

        .btn:active {
            transform: translateY(-1px);
        }

        .btn-primary {
            background: var(--gradient);
            color: white;
        }

        .btn-secondary {
            background: #6c757d;
            color: white;
        }

        .btn-info {
            background: var(--info-color);
            color: white;
        }

        .btn-icon {
            font-size: 1.2em;
        }

        /* ==================== 技巧部分 ==================== */
        .tips-section {
            background: linear-gradient(135deg, #f1f3f5 0%, #e9ecef 100%);
            padding: 25px;
            border-radius: 15px;
            margin-bottom: 30px;
        }

        .tips-section h3 {
            color: var(--dark-color);
            margin-bottom: 15px;
            font-size: 1.3em;
        }

        .tips-list {
            list-style: none;
        }

        .tips-list li {
            margin-bottom: 10px;
            padding-left: 25px;
            position: relative;
            color: #495057;
        }

        .tips-list li::before {
            content: '✨';
            position: absolute;
            left: 0;
            color: var(--primary-color);
        }

        /* ==================== 页脚 ==================== */
        .footer {
            text-align: center;
            color: #6c757d;
            padding-top: 20px;
            border-top: 2px dashed #dee2e6;
        }

        /* ==================== 通知消息 ==================== */
        .message-popup {
            position: fixed;
            top: 20px;
            right: 20px;
            padding: 15px 25px;
            border-radius: 10px;
            color: white;
            font-weight: bold;
            animation: slideInRight 0.3s;
            z-index: 1000;
            box-shadow: 0 5px 15px rgba(0,0,0,0.3);
        }

        .message-popup.success {
            background: linear-gradient(135deg, var(--success-color), #34ce57);
        }

        .message-popup.info {
            background: linear-gradient(135deg, var(--info-color), #138496);
        }

        @keyframes slideInRight {
            from {
                transform: translateX(100%);
                opacity: 0;
            }
            to {
                transform: translateX(0);
                opacity: 1;
            }
        }

        /* ==================== 加载和统计弹窗 ==================== */
        .loading {
            text-align: center;
            color: #6c757d;
            padding: 20px;
        }

        .stats-popup {
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background: white;
            padding: 30px;
            border-radius: 15px;
            box-shadow: 0 10px 40px rgba(0,0,0,0.3);
            z-index: 1001;
            text-align: center;
            animation: popIn 0.3s;
        }

        .stats-popup h3 {
            color: var(--primary-color);
            margin-bottom: 15px;
        }

        .stats-popup p {
            margin: 10px 0;
            color: var(--dark-color);
            font-size: 1.1em;
        }

        @keyframes popIn {
            from {
                opacity: 0;
                transform: translate(-50%, -60%);
            }
            to {
                opacity: 1;
                transform: translate(-50%, -50%);
            }
        }

        /* ==================== 响应式设计 ==================== */
        @media (max-width: 768px) {
            .container {
                padding: 20px;
            }
            
            h1 {
                font-size: 2em;
            }
            
            .stats-container {
                grid-template-columns: 1fr;
                gap: 10px;
            }
            
            .controls {
                grid-template-columns: 1fr;
            }
            
            .text-display {
                font-size: 1.1em;
                padding: 15px;
            }
            
            .stat-card {
                padding: 15px;
            }
            
            .stat-value {
                font-size: 1.5em;
            }
        }

        @media (max-width: 480px) {
            body {
                padding: 10px;
            }
            
            .container {
                padding: 15px;
            }
            
            h1 {
                font-size: 1.8em;
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <header>
            <h1>⌨️ 在线打字练习</h1>
            <p class="subtitle">提升打字速度，练习准确率</p>
        </header>
        
        <div class="stats-container">
            <div class="stat-card">
                <div class="stat-icon">🎯</div>
                <div class="stat-info">
                    <span class="stat-label">准确率</span>
                    <span id="accuracy" class="stat-value">0%</span>
                </div>
            </div>
            <div class="stat-card">
                <div class="stat-icon">📊</div>
                <div class="stat-info">
                    <span class="stat-label">进度</span>
                    <span id="progress" class="stat-value">0%</span>
                </div>
            </div>
            <div class="stat-card">
                <div class="stat-icon">✅</div>
                <div class="stat-info">
                    <span class="stat-label">正确/总数</span>
                    <span id="chars" class="stat-value">0/0</span>
                </div>
            </div>
        </div>

        <div class="progress-section">
            <div class="progress-header">
                <span id="text-title" class="text-title">当前练习</span>
                <span id="char-count" class="char-count">0 字符</span>
            </div>
            <div class="progress-bar-container">
                <div id="progress-bar" class="progress-bar"></div>
            </div>
        </div>

        <div class="text-display">
            <div id="target-text" class="target-text"></div>
        </div>

        <div class="input-area">
            <label for="typing-input" class="input-label">在这里开始打字：</label>
            <textarea 
                id="typing-input" 
                placeholder="点击这里开始打字练习..." 
                rows="4"
                autofocus
            ></textarea>
        </div>

        <div class="controls">
            <button id="new-text" class="btn btn-primary">
                <span class="btn-icon">🔄</span>
                新文本
            </button>
            <button id="reset" class="btn btn-secondary">
                <span class="btn-icon">↺</span>
                重置
            </button>
            <button id="copy-text" class="btn btn-info">
                <span class="btn-icon">📋</span>
                复制原文
            </button>
        </div>

        <div class="tips-section">
            <h3>💡 练习技巧</h3>
            <ul class="tips-list">
                <li>保持正确的坐姿，手腕放松</li>
                <li>先求准确，再求速度</li>
                <li>每天坚持练习15分钟</li>
                <li>注意观察常见错误模式</li>
                <li>使用键盘快捷键：Ctrl+N(新文本) Ctrl+R(重置) Esc(清空)</li>
            </ul>
        </div>

        <footer class="footer">
            <p>© 2024 在线打字练习 | 让打字变得更有趣</p>
        </footer>
    </div>

    <script>
        /**
         * 在线打字练习 - 主要交互逻辑
         */
        document.addEventListener('DOMContentLoaded', function() {
            // DOM元素
            const targetTextEl = document.getElementById('target-text');
            const typingInput = document.getElementById('typing-input');
            const accuracyEl = document.getElementById('accuracy');
            const progressEl = document.getElementById('progress');
            const charsEl = document.getElementById('chars');
            const progressBar = document.getElementById('progress-bar');
            const newTextBtn = document.getElementById('new-text');
            const resetBtn = document.getElementById('reset');
            const copyBtn = document.getElementById('copy-text');
            const textTitleEl = document.getElementById('text-title');
            const charCountEl = document.getElementById('char-count');

            // 状态变量
            let currentText = '';
            let currentTitle = '';
            let startTime = null;
            let mistakes = 0;

            // 初始化：获取第一个练习文本
            fetchNewText();

            // 事件监听
            typingInput.addEventListener('input', handleTyping);
            typingInput.addEventListener('keydown', handleKeyDown);
            newTextBtn.addEventListener('click', fetchNewText);
            resetBtn.addEventListener('click', resetPractice);
            copyBtn.addEventListener('click', copyOriginalText);

            // 获取新文本
            function fetchNewText() {
                showLoading();
                
                fetch('/get_text')
                    .then(response => {
                        if (!response.ok) {
                            throw new Error('网络响应错误');
                        }
                        return response.json();
                    })
                    .then(data => {
                        currentText = data.text;
                        currentTitle = data.title;
                        textTitleEl.textContent = `当前练习：${currentTitle}`;
                        charCountEl.textContent = `${currentText.length} 字符`;
                        displayTargetText(currentText);
                        resetPractice();
                        hideLoading();
                        showMessage('新练习已加载！', 'success');
                    })
                    .catch(error => {
                        console.error('Error:', error);
                        showMessage('加载失败，请重试', 'error');
                        hideLoading();
                    });
            }

            // 显示目标文本
            function displayTargetText(text) {
                targetTextEl.innerHTML = '';
                for (let i = 0; i < text.length; i++) {
                    const span = document.createElement('span');
                    span.textContent = text[i];
                    span.className = 'char';
                    span.dataset.index = i;
                    targetTextEl.appendChild(span);
                }
            }

            // 显示加载状态
            function showLoading() {
                targetTextEl.innerHTML = '<div class="loading">加载中...</div>';
            }

            function hideLoading() {
                // 加载完成后自动隐藏
            }

            // 处理键盘事件
            function handleKeyDown(e) {
                // 记录开始时间
                if (!startTime && typingInput.value.length === 0) {
                    startTime = new Date();
                }

                // 阻止Tab键切换焦点
                if (e.key === 'Tab') {
                    e.preventDefault();
                }
            }

            // 处理打字输入
            function handleTyping() {
                const typed = typingInput.value;
                const original = currentText;
                
                if (!original) return;

                // 高亮显示
                highlightText(typed, original);
                
                // 检查进度
                checkProgress(original, typed);
                
                // 自动滚动到当前字符
                scrollToCurrentChar();
            }

            // 高亮文本
            function highlightText(typed, original) {
                const chars = targetTextEl.children;
                let currentMistakes = 0;
                
                for (let i = 0; i < chars.length; i++) {
                    chars[i].classList.remove('correct-char', 'incorrect-char', 'current-char');
                    
                    if (i < typed.length) {
                        if (typed[i] === original[i]) {
                            chars[i].classList.add('correct-char');
                        } else {
                            chars[i].classList.add('incorrect-char');
                            currentMistakes++;
                        }
                    } else if (i === typed.length) {
                        chars[i].classList.add('current-char');
                    }
                }
                
                mistakes = currentMistakes;
            }

            // 滚动到当前字符
            function scrollToCurrentChar() {
                const currentChar = document.querySelector('.current-char');
                if (currentChar) {
                    currentChar.scrollIntoView({
                        behavior: 'smooth',
                        block: 'center',
                        inline: 'center'
                    });
                }
            }

            // 检查进度
            function checkProgress(original, typed) {
                fetch('/check_progress', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                    },
                    body: JSON.stringify({
                        original: original,
                        typed: typed
                    })
                })
                .then(response => response.json())
                .then(data => {
                    // 更新统计信息
                    accuracyEl.textContent = data.accuracy + '%';
                    progressEl.textContent = data.progress + '%';
                    charsEl.textContent = `${data.correct_chars}/${data.total_chars}`;
                    progressBar.style.width = data.progress + '%';

                    // 如果完成所有输入
                    if (typed.length === original.length) {
                        handleCompletion(data);
                    }
                })
                .catch(error => console.error('Error:', error));
            }

            // 处理完成
            function handleCompletion(data) {
                const endTime = new Date();
                const timeSpent = startTime ? (endTime - startTime) / 1000 : 0;
                
                let message = '';
                let type = '';
                
                if (data.accuracy === 100) {
                    message = `🎉 完美！用时 ${timeSpent.toFixed(1)} 秒`;
                    type = 'success';
                } else if (data.accuracy >= 90) {
                    message = `👍 很好！准确率 ${data.accuracy}%，继续加油！`;
                    type = 'success';
                } else {
                    message = `💪 完成！准确率 ${data.accuracy}%，再多练习几次吧`;
                    type = 'info';
                }
                
                showMessage(message, type);
                
                // 显示统计数据
                showCompletionStats(data, timeSpent);
            }

            // 显示完成统计
            function showCompletionStats(data, timeSpent) {
                const statsDiv = document.createElement('div');
                statsDiv.className = 'stats-popup';
                statsDiv.innerHTML = `
                    <h3>练习统计</h3>
                    <p>准确率: ${data.accuracy}%</p>
                    <p>用时: ${timeSpent.toFixed(1)} 秒</p>
                    <p>正确字符: ${data.correct_chars}/${data.total_chars}</p>
                    <p>错误次数: ${mistakes}</p>
                `;
                
                document.body.appendChild(statsDiv);
                
                setTimeout(() => {
                    statsDiv.remove();
                }, 5000);
            }

            // 重置练习
            function resetPractice() {
                typingInput.value = '';
                typingInput.focus();
                startTime = null;
                mistakes = 0;
                
                if (currentText) {
                    highlightText('', currentText);
                    
                    // 重置统计
                    accuracyEl.textContent = '0%';
                    progressEl.textContent = '0%';
                    charsEl.textContent = '0/' + currentText.length;
                    progressBar.style.width = '0%';
                }
                
                showMessage('练习已重置', 'info');
            }

            // 复制原文
            function copyOriginalText() {
                if (!currentText) {
                    showMessage('没有可复制的文本', 'error');
                    return;
                }
                
                navigator.clipboard.writeText(currentText)
                    .then(() => {
                        showMessage('原文已复制到剪贴板', 'success');
                    })
                    .catch(() => {
                        showMessage('复制失败，请手动复制', 'error');
                    });
            }

            // 显示消息
            function showMessage(msg, type = 'info') {
                const messageDiv = document.createElement('div');
                messageDiv.textContent = msg;
                messageDiv.className = `message-popup ${type}`;
                
                document.body.appendChild(messageDiv);
                
                setTimeout(() => {
                    messageDiv.remove();
                }, 3000);
            }

            // 键盘快捷键
            document.addEventListener('keydown', function(e) {
                // Ctrl + N: 新文本
                if (e.ctrlKey && e.key === 'n') {
                    e.preventDefault();
                    fetchNewText();
                }
                
                // Ctrl + R: 重置
                if (e.ctrlKey && e.key === 'r') {
                    e.preventDefault();
                    resetPractice();
                }
                
                // Esc: 清空输入
                if (e.key === 'Escape') {
                    typingInput.value = '';
                    handleTyping();
                }
            });
        });
    </script>
</body>
</html>
'''

# ==================== Flask路由 ====================


@app.route('/')
def index():
    """首页 - 返回完整的HTML页面"""
    return render_template_string(HTML_TEMPLATE)


@app.route('/get_text')
def get_text():
    """获取随机练习文本"""
    text = random.choice(practice_texts)
    return jsonify(text)


@app.route('/check_progress', methods=['POST'])
def check_progress():
    """检查打字进度"""
    data = request.json
    original = data['original']
    typed = data['typed']

    # 计算正确字符数
    correct_chars = 0
    for i, char in enumerate(typed):
        if i < len(original) and char == original[i]:
            correct_chars += 1

    # 计算准确率
    accuracy = (correct_chars / len(typed)) * 100 if typed else 0

    # 计算当前进度
    progress = (len(typed) / len(original)) * 100

    return jsonify({
        'correct_chars': correct_chars,
        'accuracy': round(accuracy, 2),
        'progress': round(progress, 2),
        'total_chars': len(original)
    })

# ==================== 程序入口 ====================


if __name__ == '__main__':
    print("=" * 50)
    print("🚀 在线打字练习网站启动中...")
    print("=" * 50)
    print("📝 访问地址: http://localhost:5000")
    print("⌨️ 键盘快捷键:")
    print("   - Ctrl+N: 新文本")
    print("   - Ctrl+R: 重置")
    print("   - Esc: 清空输入")
    print("=" * 50)
    print("💡 提示: 按 Ctrl+C 停止服务器")
    print("=" * 50)

    app.run(debug=True, host='0.0.0.0', port=5000)
