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

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

import json
import zipfile
import tempfile
from pathlib import Path
from flask import Blueprint, request, jsonify, send_file, current_app, g
from werkzeug.utils import secure_filename
from app.utils.decorators import jwt_login_required, rate_limit
from app.utils.validators import validate_file, validate_languages, validate_job_uuid
from app.utils.helpers import (
    save_uploaded_file, 
    create_response, 
    format_file_size,
    generate_download_token
)
from app.utils.exceptions import ValidationError, FileProcessingError
from app.utils.logger import get_logger
from app.models.job import TranslationJob
from app.models.log import SystemLog

files_bp = Blueprint('files', __name__, url_prefix='/files')
logger = get_logger(__name__)


@files_bp.route('/upload', methods=['POST'])
@jwt_login_required
@rate_limit(max_requests=20, per_seconds=3600)  # 每小時最多20次上傳
def upload_file():
    """檔案上傳"""
    try:
        # 檢查是否有檔案
        if 'file' not in request.files:
            return jsonify(create_response(
                success=False,
                error='NO_FILE',
                message='未選擇檔案'
            )), 400
        
        file_obj = request.files['file']
        
        # 驗證檔案
        file_info = validate_file(file_obj)
        
        # 取得翻譯設定
        source_language = request.form.get('source_language', 'auto')
        target_languages_str = request.form.get('target_languages', '[]')
        
        try:
            target_languages = json.loads(target_languages_str)
        except json.JSONDecodeError:
            return jsonify(create_response(
                success=False,
                error='INVALID_TARGET_LANGUAGES',
                message='目標語言格式錯誤'
            )), 400
        
        # 驗證語言設定
        lang_info = validate_languages(source_language, target_languages)
        
        # 建立翻譯任務
        job = TranslationJob(
            user_id=g.current_user_id,
            original_filename=file_info['filename'],
            file_extension=file_info['file_extension'],
            file_size=file_info['file_size'],
            file_path='',  # 暫時為空，稍後更新
            source_language=lang_info['source_language'],
            target_languages=lang_info['target_languages'],
            status='PENDING'
        )
        
        # 先保存到資料庫以取得 job_uuid
        from app import db
        db.session.add(job)
        db.session.commit()
        
        # 儲存檔案
        file_result = save_uploaded_file(file_obj, job.job_uuid)
        
        if not file_result['success']:
            # 如果儲存失敗，刪除任務記錄
            db.session.delete(job)
            db.session.commit()
            
            raise FileProcessingError(f"檔案儲存失敗: {file_result['error']}")
        
        # 更新任務的檔案路徑
        job.file_path = file_result['file_path']
        
        # 新增原始檔案記錄
        job.add_original_file(
            filename=file_result['filename'],
            file_path=file_result['file_path'],
            file_size=file_result['file_size']
        )
        
        db.session.commit()
        
        # 計算佇列位置
        queue_position = TranslationJob.get_queue_position(job.job_uuid)
        
        # 記錄日誌
        SystemLog.info(
            'files.upload',
            f'File uploaded successfully: {file_info["filename"]}',
            user_id=g.current_user_id,
            job_id=job.id,
            extra_data={
                'filename': file_info['filename'],
                'file_size': file_info['file_size'],
                'source_language': source_language,
                'target_languages': target_languages
            }
        )
        
        logger.info(f"File uploaded successfully: {job.job_uuid} - {file_info['filename']}")
        
        # 觸發翻譯任務
        try:
            from app.tasks.translation import process_translation_job
            
            # 嘗試使用 Celery 異步處理
            try:
                task = process_translation_job.delay(job.id)
                logger.info(f"Translation task queued with Celery: {task.id} for job {job.job_uuid}")
            except Exception as celery_error:
                logger.warning(f"Celery not available, falling back to synchronous processing: {str(celery_error)}")
                
                # Celery 不可用時，使用同步處理
                try:
                    from app.services.translation_service import TranslationService
                    service = TranslationService()
                    
                    # 在後台執行翻譯（同步處理）
                    logger.info(f"Starting synchronous translation for job {job.job_uuid}")
                    result = service.translate_document(job.job_uuid)
                    logger.info(f"Synchronous translation completed for job {job.job_uuid}: {result}")
                    
                except Exception as sync_error:
                    logger.error(f"Synchronous translation failed for job {job.job_uuid}: {str(sync_error)}")
                    job.update_status('FAILED', error_message=f"翻譯處理失敗: {str(sync_error)}")
                    db.session.commit()
                    
        except Exception as e:
            logger.error(f"Failed to process translation for job {job.job_uuid}: {str(e)}")
            job.update_status('FAILED', error_message=f"任務處理失敗: {str(e)}")
            db.session.commit()
        
        return jsonify(create_response(
            success=True,
            data={
                'job_uuid': job.job_uuid,
                'original_filename': job.original_filename,
                'file_size': job.file_size,
                'file_size_formatted': format_file_size(job.file_size),
                'source_language': job.source_language,
                'target_languages': job.target_languages,
                'status': job.status,
                'queue_position': queue_position,
                'created_at': job.created_at.isoformat()
            },
            message='檔案上傳成功，已加入翻譯佇列'
        ))
    
    except ValidationError as e:
        logger.warning(f"File upload validation error: {str(e)}")
        return jsonify(create_response(
            success=False,
            error=e.error_code,
            message=str(e)
        )), 400
    
    except FileProcessingError as e:
        logger.error(f"File processing error: {str(e)}")
        return jsonify(create_response(
            success=False,
            error='FILE_PROCESSING_ERROR',
            message=str(e)
        )), 500
    
    except Exception as e:
        logger.error(f"File upload error: {str(e)}")
        
        SystemLog.error(
            'files.upload_error',
            f'File upload failed: {str(e)}',
            user_id=g.current_user_id,
            extra_data={'error': str(e)}
        )
        
        return jsonify(create_response(
            success=False,
            error='SYSTEM_ERROR',
            message='檔案上傳失敗'
        )), 500


@files_bp.route('/<job_uuid>/download/<language_code>', methods=['GET'])
@jwt_login_required
def download_file(job_uuid, language_code):
    """下載翻譯檔案"""
    try:
        # 驗證 UUID 格式
        validate_job_uuid(job_uuid)
        
        # 取得任務
        job = TranslationJob.query.filter_by(job_uuid=job_uuid).first()
        
        if not job:
            return jsonify(create_response(
                success=False,
                error='JOB_NOT_FOUND',
                message='任務不存在'
            )), 404
        
        # 檢查權限
        if job.user_id != g.current_user_id and not g.is_admin:
            return jsonify(create_response(
                success=False,
                error='PERMISSION_DENIED',
                message='無權限存取此檔案'
            )), 403
        
        # 檢查任務狀態
        if job.status != 'COMPLETED':
            return jsonify(create_response(
                success=False,
                error='JOB_NOT_COMPLETED',
                message='任務尚未完成'
            )), 400
        
        # 尋找對應的翻譯檔案
        translated_file = None
        for file_record in job.files:
            if file_record.file_type == 'TRANSLATED' and file_record.language_code == language_code:
                translated_file = file_record
                break
        
        if not translated_file:
            return jsonify(create_response(
                success=False,
                error='FILE_NOT_FOUND',
                message=f'找不到 {language_code} 的翻譯檔案'
            )), 404
        
        # 檢查檔案是否存在
        file_path = Path(translated_file.file_path)
        if not file_path.exists():
            logger.error(f"File not found on disk: {file_path}")
            
            return jsonify(create_response(
                success=False,
                error='FILE_NOT_FOUND_ON_DISK',
                message='檔案在伺服器上不存在'
            )), 404
        
        # 記錄下載日誌
        SystemLog.info(
            'files.download',
            f'File downloaded: {translated_file.filename}',
            user_id=g.current_user_id,
            job_id=job.id,
            extra_data={
                'filename': translated_file.filename,
                'language_code': language_code,
                'file_size': translated_file.file_size
            }
        )
        
        logger.info(f"File downloaded: {job.job_uuid} - {language_code}")
        
        # 發送檔案
        return send_file(
            str(file_path),
            as_attachment=True,
            download_name=translated_file.filename,
            mimetype='application/octet-stream'
        )
    
    except ValidationError as e:
        return jsonify(create_response(
            success=False,
            error=e.error_code,
            message=str(e)
        )), 400
    
    except Exception as e:
        logger.error(f"File download error: {str(e)}")
        
        return jsonify(create_response(
            success=False,
            error='SYSTEM_ERROR',
            message='檔案下載失敗'
        )), 500


@files_bp.route('/<job_uuid>/download/original', methods=['GET'])
@jwt_login_required
def download_original_file(job_uuid):
    """下載原始檔案"""
    try:
        # 驗證 UUID 格式
        validate_job_uuid(job_uuid)
        
        # 取得任務
        job = TranslationJob.query.filter_by(job_uuid=job_uuid).first()
        
        if not job:
            return jsonify(create_response(
                success=False,
                error='JOB_NOT_FOUND',
                message='任務不存在'
            )), 404
        
        # 檢查權限
        if job.user_id != g.current_user_id and not g.is_admin:
            return jsonify(create_response(
                success=False,
                error='PERMISSION_DENIED',
                message='無權限存取此檔案'
            )), 403
        
        # 取得原始檔案
        original_file = job.get_original_file()
        
        if not original_file:
            return jsonify(create_response(
                success=False,
                error='ORIGINAL_FILE_NOT_FOUND',
                message='找不到原始檔案記錄'
            )), 404
        
        # 檢查檔案是否存在
        file_path = Path(original_file.file_path)
        if not file_path.exists():
            logger.error(f"Original file not found on disk: {file_path}")
            
            return jsonify(create_response(
                success=False,
                error='FILE_NOT_FOUND_ON_DISK',
                message='原始檔案在伺服器上不存在'
            )), 404
        
        # 記錄下載日誌
        SystemLog.info(
            'files.download_original',
            f'Original file downloaded: {original_file.filename}',
            user_id=g.current_user_id,
            job_id=job.id,
            extra_data={
                'filename': original_file.filename,
                'file_size': original_file.file_size
            }
        )
        
        logger.info(f"Original file downloaded: {job.job_uuid}")
        
        # 發送檔案
        return send_file(
            str(file_path),
            as_attachment=True,
            download_name=job.original_filename,
            mimetype='application/octet-stream'
        )
    
    except ValidationError as e:
        return jsonify(create_response(
            success=False,
            error=e.error_code,
            message=str(e)
        )), 400
    
    except Exception as e:
        logger.error(f"Original file download error: {str(e)}")
        
        return jsonify(create_response(
            success=False,
            error='SYSTEM_ERROR',
            message='原始檔案下載失敗'
        )), 500


@files_bp.route('/supported-formats', methods=['GET'])
def get_supported_formats():
    """取得支援的檔案格式"""
    try:
        formats = {
            '.docx': {
                'name': 'Word 文件 (.docx)',
                'description': 'Microsoft Word 2007+ 格式',
                'icon': 'file-word'
            },
            '.doc': {
                'name': 'Word 文件 (.doc)',
                'description': 'Microsoft Word 97-2003 格式',
                'icon': 'file-word'
            },
            '.pptx': {
                'name': 'PowerPoint 簡報 (.pptx)',
                'description': 'Microsoft PowerPoint 2007+ 格式',
                'icon': 'file-powerpoint'
            },
            '.xlsx': {
                'name': 'Excel 試算表 (.xlsx)',
                'description': 'Microsoft Excel 2007+ 格式',
                'icon': 'file-excel'
            },
            '.xls': {
                'name': 'Excel 試算表 (.xls)',
                'description': 'Microsoft Excel 97-2003 格式',
                'icon': 'file-excel'
            },
            '.pdf': {
                'name': 'PDF 文件 (.pdf)',
                'description': 'Portable Document Format',
                'icon': 'file-pdf'
            }
        }
        
        max_size = current_app.config.get('MAX_CONTENT_LENGTH', 26214400)
        
        return jsonify(create_response(
            success=True,
            data={
                'supported_formats': formats,
                'max_file_size': max_size,
                'max_file_size_formatted': format_file_size(max_size)
            }
        ))
    
    except Exception as e:
        logger.error(f"Get supported formats error: {str(e)}")
        
        return jsonify(create_response(
            success=False,
            error='SYSTEM_ERROR',
            message='取得支援格式失敗'
        )), 500


@files_bp.route('/supported-languages', methods=['GET'])
def get_supported_languages():
    """取得支援的語言"""
    try:
        from app.utils.helpers import get_supported_languages
        
        languages = get_supported_languages()
        
        return jsonify(create_response(
            success=True,
            data={
                'supported_languages': languages
            }
        ))
    
    except Exception as e:
        logger.error(f"Get supported languages error: {str(e)}")
        
        return jsonify(create_response(
            success=False,
            error='SYSTEM_ERROR',
            message='取得支援語言失敗'
        )), 500


@files_bp.route('/<job_uuid>/download/batch', methods=['GET'])
@jwt_login_required
def download_batch_files(job_uuid):
    """批量下載所有翻譯檔案為 ZIP"""
    try:
        # 驗證 UUID 格式
        validate_job_uuid(job_uuid)
        
        # 取得任務
        job = TranslationJob.query.filter_by(job_uuid=job_uuid).first()
        
        if not job:
            return jsonify(create_response(
                success=False,
                error='JOB_NOT_FOUND',
                message='任務不存在'
            )), 404
        
        # 檢查權限
        if job.user_id != g.current_user_id and not g.is_admin:
            return jsonify(create_response(
                success=False,
                error='PERMISSION_DENIED',
                message='無權限存取此檔案'
            )), 403
        
        # 檢查任務狀態
        if job.status != 'COMPLETED':
            return jsonify(create_response(
                success=False,
                error='JOB_NOT_COMPLETED',
                message='任務尚未完成'
            )), 400
        
        # 收集所有翻譯檔案
        translated_files = job.get_translated_files()
        
        if not translated_files:
            return jsonify(create_response(
                success=False,
                error='NO_TRANSLATED_FILES',
                message='沒有找到翻譯檔案'
            )), 404
        
        # 建立臨時 ZIP 檔案
        temp_dir = tempfile.gettempdir()
        zip_filename = f"{job.original_filename.split('.')[0]}_translations_{job.job_uuid[:8]}.zip"
        zip_path = Path(temp_dir) / zip_filename
        
        try:
            with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zip_file:
                files_added = 0
                
                # 添加原始檔案
                original_file = job.get_original_file()
                if original_file and Path(original_file.file_path).exists():
                    zip_file.write(
                        original_file.file_path,
                        f"original/{original_file.filename}"
                    )
                    files_added += 1
                
                # 添加所有翻譯檔案（避免重複）
                added_files = set()  # 追蹤已添加的檔案，避免重複
                for tf in translated_files:
                    file_path = Path(tf.file_path)
                    if file_path.exists():
                        # 按語言建立資料夾結構
                        archive_name = f"{tf.language_code}/{tf.filename}"
                        
                        # 檢查是否已經添加過這個檔案
                        if archive_name not in added_files:
                            zip_file.write(str(file_path), archive_name)
                            added_files.add(archive_name)
                            files_added += 1
                    else:
                        logger.warning(f"Translation file not found: {tf.file_path}")
                
                if files_added == 0:
                    return jsonify(create_response(
                        success=False,
                        error='NO_FILES_TO_ZIP',
                        message='沒有可用的檔案進行壓縮'
                    )), 404
            
            # 檢查 ZIP 檔案是否建立成功
            if not zip_path.exists():
                return jsonify(create_response(
                    success=False,
                    error='ZIP_CREATION_FAILED',
                    message='ZIP 檔案建立失敗'
                )), 500
            
            # 記錄下載日誌
            SystemLog.info(
                'files.download_batch',
                f'Batch files downloaded: {zip_filename}',
                user_id=g.current_user_id,
                job_id=job.id,
                extra_data={
                    'zip_filename': zip_filename,
                    'files_count': files_added,
                    'job_uuid': job_uuid
                }
            )
            
            logger.info(f"Batch files downloaded: {job.job_uuid} - {files_added} files in ZIP")
            
            # 發送 ZIP 檔案
            return send_file(
                str(zip_path),
                as_attachment=True,
                download_name=zip_filename,
                mimetype='application/zip'
            )
        
        finally:
            # 清理臨時檔案（在發送後會自動清理）
            pass
    
    except ValidationError as e:
        return jsonify(create_response(
            success=False,
            error=e.error_code,
            message=str(e)
        )), 400
    
    except Exception as e:
        logger.error(f"Batch download error: {str(e)}")
        
        return jsonify(create_response(
            success=False,
            error='SYSTEM_ERROR',
            message='批量下載失敗'
        )), 500