#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
檔案管理 API 測試

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

import pytest
import io
import json
from unittest.mock import patch, MagicMock
from app.models.job import TranslationJob


class TestFilesAPI:
    """檔案管理 API 測試類別"""
    
    def test_upload_file_success(self, authenticated_client, auth_user):
        """測試成功上傳檔案"""
        # 建立測試檔案
        file_data = b'Mock DOCX file content'
        file_obj = (io.BytesIO(file_data), 'test.docx')
        
        with patch('app.utils.helpers.save_uploaded_file') as mock_save:
            mock_save.return_value = {
                'success': True,
                'filename': 'original_test_12345678.docx',
                'file_path': '/tmp/test_job_uuid/original_test_12345678.docx',
                'file_size': len(file_data)
            }
            
            response = authenticated_client.post('/api/v1/files/upload', data={
                'file': file_obj,
                'source_language': 'auto',
                'target_languages': json.dumps(['en', 'vi'])
            })
            
            assert response.status_code == 200
            data = response.get_json()
            assert data['success'] is True
            assert 'job_uuid' in data['data']
            assert data['data']['original_filename'] == 'test.docx'
    
    def test_upload_file_no_file(self, authenticated_client):
        """測試未選擇檔案"""
        response = authenticated_client.post('/api/v1/files/upload', data={
            'source_language': 'auto',
            'target_languages': json.dumps(['en'])
        })
        
        assert response.status_code == 400
        data = response.get_json()
        assert data['success'] is False
        assert data['error'] == 'NO_FILE'
    
    def test_upload_file_invalid_type(self, authenticated_client):
        """測試上傳無效檔案類型"""
        file_data = b'Mock text file content'
        file_obj = (io.BytesIO(file_data), 'test.txt')
        
        response = authenticated_client.post('/api/v1/files/upload', data={
            'file': file_obj,
            'source_language': 'auto',
            'target_languages': json.dumps(['en'])
        })
        
        assert response.status_code == 400
        data = response.get_json()
        assert data['success'] is False
        assert data['error'] == 'INVALID_FILE_TYPE'
    
    def test_upload_file_too_large(self, authenticated_client, app):
        """測試上傳過大檔案"""
        # 建立超過限制的檔案（26MB+）
        large_file_data = b'x' * (26 * 1024 * 1024 + 1)
        file_obj = (io.BytesIO(large_file_data), 'large.docx')
        
        response = authenticated_client.post('/api/v1/files/upload', data={
            'file': file_obj,
            'source_language': 'auto',
            'target_languages': json.dumps(['en'])
        })
        
        assert response.status_code == 400
        data = response.get_json()
        assert data['success'] is False
        assert data['error'] == 'FILE_TOO_LARGE'
    
    def test_upload_file_invalid_target_languages(self, authenticated_client):
        """測試無效的目標語言"""
        file_data = b'Mock DOCX file content'
        file_obj = (io.BytesIO(file_data), 'test.docx')
        
        response = authenticated_client.post('/api/v1/files/upload', data={
            'file': file_obj,
            'source_language': 'auto',
            'target_languages': 'invalid_json'
        })
        
        assert response.status_code == 400
        data = response.get_json()
        assert data['success'] is False
        assert data['error'] == 'INVALID_TARGET_LANGUAGES'
    
    def test_upload_file_empty_target_languages(self, authenticated_client):
        """測試空的目標語言"""
        file_data = b'Mock DOCX file content'
        file_obj = (io.BytesIO(file_data), 'test.docx')
        
        response = authenticated_client.post('/api/v1/files/upload', data={
            'file': file_obj,
            'source_language': 'auto',
            'target_languages': json.dumps([])
        })
        
        assert response.status_code == 400
        data = response.get_json()
        assert data['success'] is False
        assert data['error'] == 'NO_TARGET_LANGUAGES'
    
    def test_upload_file_without_auth(self, client):
        """測試未認證上傳檔案"""
        file_data = b'Mock DOCX file content'
        file_obj = (io.BytesIO(file_data), 'test.docx')
        
        response = client.post('/api/v1/files/upload', data={
            'file': file_obj,
            'source_language': 'auto',
            'target_languages': json.dumps(['en'])
        })
        
        assert response.status_code == 401
        data = response.get_json()
        assert data['success'] is False
        assert data['error'] == 'AUTHENTICATION_REQUIRED'
    
    def test_download_translated_file_success(self, authenticated_client, sample_job, auth_user):
        """測試成功下載翻譯檔案"""
        # 設定任務為已完成
        sample_job.update_status('COMPLETED')
        
        # 添加翻譯檔案記錄
        sample_job.add_translated_file(
            language_code='en',
            filename='test_en_translated.docx',
            file_path='/tmp/test_en_translated.docx',
            file_size=1024
        )
        
        with patch('pathlib.Path.exists') as mock_exists, \
             patch('flask.send_file') as mock_send_file:
            
            mock_exists.return_value = True
            mock_send_file.return_value = 'file_content'
            
            response = authenticated_client.get(f'/api/v1/files/{sample_job.job_uuid}/download/en')
            
            # send_file 被呼叫表示成功
            mock_send_file.assert_called_once()
    
    def test_download_file_not_found(self, authenticated_client, sample_job):
        """測試下載不存在的檔案"""
        response = authenticated_client.get(f'/api/v1/files/nonexistent-uuid/download/en')
        
        assert response.status_code == 404
        data = response.get_json()
        assert data['success'] is False
        assert data['error'] == 'JOB_NOT_FOUND'
    
    def test_download_file_permission_denied(self, authenticated_client, sample_job, app):
        """測試下載他人檔案"""
        # 建立另一個使用者的任務
        from app.models.user import User
        from app import db
        
        with app.app_context():
            other_user = User(
                username='otheruser',
                display_name='Other User',
                email='other@panjit.com.tw',
                department='IT',
                is_admin=False
            )
            db.session.add(other_user)
            db.session.commit()
            
            other_job = TranslationJob(
                user_id=other_user.id,
                original_filename='other.docx',
                file_extension='.docx',
                file_size=1024,
                file_path='/tmp/other.docx',
                source_language='auto',
                target_languages=['en'],
                status='COMPLETED'
            )
            db.session.add(other_job)
            db.session.commit()
            
            response = authenticated_client.get(f'/api/v1/files/{other_job.job_uuid}/download/en')
            
            assert response.status_code == 403
            data = response.get_json()
            assert data['success'] is False
            assert data['error'] == 'PERMISSION_DENIED'
    
    def test_download_file_not_completed(self, authenticated_client, sample_job):
        """測試下載未完成任務的檔案"""
        response = authenticated_client.get(f'/api/v1/files/{sample_job.job_uuid}/download/en')
        
        assert response.status_code == 400
        data = response.get_json()
        assert data['success'] is False
        assert data['error'] == 'JOB_NOT_COMPLETED'
    
    def test_download_original_file_success(self, authenticated_client, sample_job):
        """測試下載原始檔案"""
        # 添加原始檔案記錄
        sample_job.add_original_file(
            filename='original_test.docx',
            file_path='/tmp/original_test.docx',
            file_size=1024
        )
        
        with patch('pathlib.Path.exists') as mock_exists, \
             patch('flask.send_file') as mock_send_file:
            
            mock_exists.return_value = True
            mock_send_file.return_value = 'file_content'
            
            response = authenticated_client.get(f'/api/v1/files/{sample_job.job_uuid}/download/original')
            
            mock_send_file.assert_called_once()
    
    def test_get_supported_formats(self, client):
        """測試取得支援的檔案格式"""
        response = client.get('/api/v1/files/supported-formats')
        
        assert response.status_code == 200
        data = response.get_json()
        assert data['success'] is True
        assert 'supported_formats' in data['data']
        assert 'max_file_size' in data['data']
        
        # 檢查是否包含基本格式
        formats = data['data']['supported_formats']
        assert '.docx' in formats
        assert '.pdf' in formats
    
    def test_get_supported_languages(self, client):
        """測試取得支援的語言"""
        response = client.get('/api/v1/files/supported-languages')
        
        assert response.status_code == 200
        data = response.get_json()
        assert data['success'] is True
        assert 'supported_languages' in data['data']
        
        # 檢查是否包含基本語言
        languages = data['data']['supported_languages']
        assert 'en' in languages
        assert 'zh-TW' in languages
        assert 'auto' in languages