#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
資料模型測試

Author: PANJIT IT Team
Created: 2024-01-28
Modified: 2024-01-28
"""

import pytest
from datetime import datetime, timedelta
from app.models.user import User
from app.models.job import TranslationJob, JobFile
from app.models.cache import TranslationCache
from app.models.stats import APIUsageStats
from app.models.log import SystemLog
from app import db


class TestUserModel:
    """使用者模型測試"""
    
    def test_create_user(self, app):
        """測試建立使用者"""
        with app.app_context():
            user = User(
                username='testuser',
                display_name='Test User',
                email='test@example.com',
                department='IT',
                is_admin=False
            )
            
            db.session.add(user)
            db.session.commit()
            
            assert user.id is not None
            assert user.username == 'testuser'
            assert user.is_admin is False
    
    def test_user_to_dict(self, app, auth_user):
        """測試使用者轉字典"""
        with app.app_context():
            user_dict = auth_user.to_dict()
            
            assert 'id' in user_dict
            assert 'username' in user_dict
            assert 'display_name' in user_dict
            assert 'email' in user_dict
            assert user_dict['username'] == auth_user.username
    
    def test_user_get_or_create_existing(self, app, auth_user):
        """測試取得已存在的使用者"""
        with app.app_context():
            user = User.get_or_create(
                username=auth_user.username,
                display_name='Updated Name',
                email=auth_user.email
            )
            
            assert user.id == auth_user.id
            assert user.display_name == 'Updated Name'  # 應該更新
    
    def test_user_get_or_create_new(self, app):
        """測試建立新使用者"""
        with app.app_context():
            user = User.get_or_create(
                username='newuser',
                display_name='New User',
                email='new@example.com'
            )
            
            assert user.id is not None
            assert user.username == 'newuser'
    
    def test_update_last_login(self, app, auth_user):
        """測試更新最後登入時間"""
        with app.app_context():
            old_login_time = auth_user.last_login
            auth_user.update_last_login()
            
            assert auth_user.last_login is not None
            if old_login_time:
                assert auth_user.last_login > old_login_time


class TestTranslationJobModel:
    """翻譯任務模型測試"""
    
    def test_create_translation_job(self, app, auth_user):
        """測試建立翻譯任務"""
        with app.app_context():
            job = TranslationJob(
                user_id=auth_user.id,
                original_filename='test.docx',
                file_extension='.docx',
                file_size=1024,
                file_path='/tmp/test.docx',
                source_language='auto',
                target_languages=['en', 'vi'],
                status='PENDING'
            )
            
            db.session.add(job)
            db.session.commit()
            
            assert job.id is not None
            assert job.job_uuid is not None
            assert len(job.job_uuid) == 36  # UUID 格式
    
    def test_job_to_dict(self, app, sample_job):
        """測試任務轉字典"""
        with app.app_context():
            job_dict = sample_job.to_dict()
            
            assert 'id' in job_dict
            assert 'job_uuid' in job_dict
            assert 'original_filename' in job_dict
            assert 'target_languages' in job_dict
            assert job_dict['job_uuid'] == sample_job.job_uuid
    
    def test_update_status(self, app, sample_job):
        """測試更新任務狀態"""
        with app.app_context():
            old_updated_at = sample_job.updated_at
            sample_job.update_status('PROCESSING', progress=50.0)
            
            assert sample_job.status == 'PROCESSING'
            assert sample_job.progress == 50.0
            assert sample_job.processing_started_at is not None
            assert sample_job.updated_at > old_updated_at
    
    def test_add_original_file(self, app, sample_job):
        """測試新增原始檔案記錄"""
        with app.app_context():
            file_record = sample_job.add_original_file(
                filename='test.docx',
                file_path='/tmp/test.docx',
                file_size=1024
            )
            
            assert file_record.id is not None
            assert file_record.file_type == 'ORIGINAL'
            assert file_record.filename == 'test.docx'
    
    def test_add_translated_file(self, app, sample_job):
        """測試新增翻譯檔案記錄"""
        with app.app_context():
            file_record = sample_job.add_translated_file(
                language_code='en',
                filename='test_en.docx',
                file_path='/tmp/test_en.docx',
                file_size=1200
            )
            
            assert file_record.id is not None
            assert file_record.file_type == 'TRANSLATED'
            assert file_record.language_code == 'en'
    
    def test_can_retry(self, app, sample_job):
        """測試是否可以重試"""
        with app.app_context():
            # PENDING 狀態不能重試
            assert not sample_job.can_retry()
            
            # FAILED 狀態且重試次數 < 3 可以重試
            sample_job.update_status('FAILED')
            sample_job.retry_count = 2
            assert sample_job.can_retry()
            
            # 重試次數達到上限不能重試
            sample_job.retry_count = 3
            assert not sample_job.can_retry()


class TestTranslationCacheModel:
    """翻譯快取模型測試"""
    
    def test_save_and_get_translation(self, app):
        """測試儲存和取得翻譯快取"""
        with app.app_context():
            source_text = "Hello, world!"
            translated_text = "你好，世界！"
            
            # 儲存翻譯
            result = TranslationCache.save_translation(
                source_text=source_text,
                source_language='en',
                target_language='zh-TW',
                translated_text=translated_text
            )
            
            assert result is True
            
            # 取得翻譯
            cached_translation = TranslationCache.get_translation(
                source_text=source_text,
                source_language='en',
                target_language='zh-TW'
            )
            
            assert cached_translation == translated_text
    
    def test_get_nonexistent_translation(self, app):
        """測試取得不存在的翻譯"""
        with app.app_context():
            cached_translation = TranslationCache.get_translation(
                source_text="Nonexistent text",
                source_language='en',
                target_language='zh-TW'
            )
            
            assert cached_translation is None
    
    def test_generate_hash(self):
        """測試生成文字雜湊"""
        text = "Hello, world!"
        hash1 = TranslationCache.generate_hash(text)
        hash2 = TranslationCache.generate_hash(text)
        
        assert hash1 == hash2
        assert len(hash1) == 64  # SHA256 雜湊長度


class TestAPIUsageStatsModel:
    """API 使用統計模型測試"""
    
    def test_record_api_call(self, app, auth_user, sample_job):
        """測試記錄 API 呼叫"""
        with app.app_context():
            metadata = {
                'usage': {
                    'prompt_tokens': 10,
                    'completion_tokens': 5,
                    'total_tokens': 15,
                    'prompt_unit_price': 0.0001,
                    'prompt_price_unit': 'USD'
                }
            }
            
            stats = APIUsageStats.record_api_call(
                user_id=auth_user.id,
                job_id=sample_job.id,
                api_endpoint='/chat-messages',
                metadata=metadata,
                response_time_ms=1000
            )
            
            assert stats.id is not None
            assert stats.prompt_tokens == 10
            assert stats.total_tokens == 15
            assert stats.cost == 10 * 0.0001  # prompt_tokens * prompt_unit_price
    
    def test_get_user_statistics(self, app, auth_user):
        """測試取得使用者統計"""
        with app.app_context():
            stats = APIUsageStats.get_user_statistics(auth_user.id)
            
            assert 'total_calls' in stats
            assert 'successful_calls' in stats
            assert 'total_cost' in stats


class TestSystemLogModel:
    """系統日誌模型測試"""
    
    def test_create_log_entry(self, app, auth_user):
        """測試建立日誌項目"""
        with app.app_context():
            log = SystemLog.log(
                level='INFO',
                module='test_module',
                message='Test message',
                user_id=auth_user.id
            )
            
            assert log.id is not None
            assert log.level == 'INFO'
            assert log.module == 'test_module'
            assert log.message == 'Test message'
    
    def test_log_convenience_methods(self, app):
        """測試日誌便利方法"""
        with app.app_context():
            # 測試不同等級的日誌方法
            info_log = SystemLog.info('test', 'Info message')
            warning_log = SystemLog.warning('test', 'Warning message')
            error_log = SystemLog.error('test', 'Error message')
            
            assert info_log.level == 'INFO'
            assert warning_log.level == 'WARNING'
            assert error_log.level == 'ERROR'
    
    def test_get_logs_with_filters(self, app):
        """測試帶篩選條件的日誌查詢"""
        with app.app_context():
            # 建立測試日誌
            SystemLog.info('module1', 'Test message 1')
            SystemLog.error('module2', 'Test message 2')
            
            # 按等級篩選
            info_logs = SystemLog.get_logs(level='INFO', limit=10)
            assert len([log for log in info_logs if log.level == 'INFO']) > 0
            
            # 按模組篩選
            module1_logs = SystemLog.get_logs(module='module1', limit=10)
            assert len([log for log in module1_logs if 'module1' in log.module]) > 0