"""
图片解析模块

该模块提供图片文件的解析功能，包括名片识别、证件照处理等。
"""

import logging
from datetime import datetime
import json
import os
import uuid
from typing import Dict, Any, Optional, List, Tuple
from app.core.data_parse.time_utils import get_east_asia_time_str, get_east_asia_timestamp, get_east_asia_isoformat, get_east_asia_date_str
import base64
from PIL import Image
import io
from openai import OpenAI
import boto3
from botocore.config import Config
from app.config.config import DevelopmentConfig, ProductionConfig

# 使用配置变量
config = ProductionConfig()

# MinIO 配置
minio_url = f"{'https' if config.MINIO_SECURE else 'http'}://{config.MINIO_HOST}"
minio_access_key = config.MINIO_USER
minio_secret_key = config.MINIO_PASSWORD
minio_bucket = config.MINIO_BUCKET


def get_minio_client():
    """获取MinIO客户端连接"""
    try:
        logging.info(f"尝试连接MinIO服务器: {minio_url}")
        
        minio_client = boto3.client(
            's3',
            endpoint_url=minio_url,
            aws_access_key_id=minio_access_key,
            aws_secret_access_key=minio_secret_key,
            config=Config(
                signature_version='s3v4',
                retries={'max_attempts': 3, 'mode': 'standard'},
                connect_timeout=10,
                read_timeout=30
            )
        )
        
        # 确保存储桶存在
        buckets = minio_client.list_buckets()
        bucket_names = [bucket['Name'] for bucket in buckets.get('Buckets', [])]
        logging.info(f"成功连接到MinIO服务器，现有存储桶: {bucket_names}")
        
        if minio_bucket not in bucket_names:
            logging.info(f"创建存储桶: {minio_bucket}")
            minio_client.create_bucket(Bucket=minio_bucket)
            
        return minio_client
    except Exception as e:
        logging.error(f"MinIO连接错误: {str(e)}")
        return None


def parse_business_card_image(image_path: str, task_id: Optional[str] = None) -> Dict[str, Any]:
    """
    解析名片图片
    
    Args:
        image_path (str): 名片图片路径
        task_id (str, optional): 关联的任务ID
        
    Returns:
        Dict[str, Any]: 解析结果
    """
    try:
        logging.info(f"开始解析名片图片: {image_path}")
        
        # 验证文件存在性和格式
        validation_result = validate_image_file(image_path)
        if not validation_result['is_valid']:
            return {
                'success': False,
                'error': validation_result['error'],
                'data': None
            }
        
        # 获取图片信息
        image_info = get_image_info(image_path)
        
        # TODO: 集成OCR引擎进行名片文字识别
        # 这里应该调用OCR服务（如百度OCR、腾讯OCR等）来识别名片上的文字
        
        # 模拟名片识别结果
        card_data = _extract_business_card_info(image_path)
        
        result = {
            'success': True,
            'error': None,
            'data': {
                'personal_info': card_data,
                'image_info': image_info,
                'parse_time': get_east_asia_isoformat(),
                'task_id': task_id,
                'confidence_score': 0.85  # 模拟置信度分数
            }
        }
        
        logging.info(f"名片图片解析完成: {image_path}")
        return result
        
    except Exception as e:
        error_msg = f"解析名片图片失败: {str(e)}"
        logging.error(error_msg, exc_info=True)
        
        return {
            'success': False,
            'error': error_msg,
            'data': None
        }


def parse_portrait_image(image_path: str, task_id: Optional[str] = None) -> Dict[str, Any]:
    """
    解析证件照图片
    
    Args:
        image_path (str): 证件照图片路径
        task_id (str, optional): 关联的任务ID
        
    Returns:
        Dict[str, Any]: 解析结果
    """
    try:
        logging.info(f"开始解析证件照图片: {image_path}")
        
        # 验证文件
        validation_result = validate_image_file(image_path)
        if not validation_result['is_valid']:
            return {
                'success': False,
                'error': validation_result['error'],
                'data': None
            }
        
        # 获取图片信息
        image_info = get_image_info(image_path)
        
        # 检查是否为合格的证件照
        portrait_analysis = _analyze_portrait_quality(image_path)
        
        result = {
            'success': True,
            'error': None,
            'data': {
                'image_info': image_info,
                'portrait_analysis': portrait_analysis,
                'parse_time': get_east_asia_isoformat(),
                'task_id': task_id
            }
        }
        
        logging.info(f"证件照图片解析完成: {image_path}")
        return result
        
    except Exception as e:
        error_msg = f"解析证件照图片失败: {str(e)}"
        logging.error(error_msg, exc_info=True)
        
        return {
            'success': False,
            'error': error_msg,
            'data': None
        }


def validate_image_file(image_path: str) -> Dict[str, Any]:
    """
    验证图片文件的有效性，支持本地路径和MinIO URL
    
    Args:
        image_path (str): 图片文件路径或MinIO URL
        
    Returns:
        Dict[str, Any]: 验证结果
    """
    try:
        # 检查是否是MinIO URL
        if image_path.startswith('http://') or image_path.startswith('https://'):
            # 处理MinIO URL
            try:
                # 从URL提取文件扩展名
                from urllib.parse import urlparse
                parsed_url = urlparse(image_path)
                file_ext = os.path.splitext(parsed_url.path)[1].lower()
                
                # 检查文件扩展名
                allowed_extensions = {'.jpg', '.jpeg', '.png', '.bmp', '.gif'}
                if file_ext not in allowed_extensions:
                    return {
                        'is_valid': False,
                        'error': f'不支持的图片格式: {file_ext}，支持的格式: {", ".join(allowed_extensions)}'
                    }
                
                # 尝试从MinIO获取图片数据进行验证
                minio_client = get_minio_client()
                if not minio_client:
                    return {
                        'is_valid': False,
                        'error': '无法连接到MinIO服务器'
                    }
                
                # 提取对象键
                path_parts = parsed_url.path.strip('/').split('/', 1)
                if len(path_parts) < 2:
                    return {
                        'is_valid': False,
                        'error': f'无效的MinIO URL格式: {image_path}'
                    }
                
                object_key = path_parts[1]  # 跳过bucket名称
                
                # 从MinIO获取图片数据
                try:
                    response = minio_client.get_object(Bucket=minio_bucket, Key=object_key)
                    image_data = response['Body'].read()
                    
                    # 验证图片完整性
                    from io import BytesIO
                    with Image.open(BytesIO(image_data)) as img:
                        img.verify()
                    
                    return {
                        'is_valid': True,
                        'error': None
                    }
                except Exception as minio_error:
                    return {
                        'is_valid': False,
                        'error': f'图片文件不存在: {image_path}'
                    }
                    
            except Exception as url_error:
                return {
                    'is_valid': False,
                    'error': f'处理MinIO URL失败: {str(url_error)}'
                }
        else:
            # 处理本地文件路径
            # 检查文件是否存在
            if not os.path.exists(image_path):
                return {
                    'is_valid': False,
                    'error': f'图片文件不存在: {image_path}'
                }
            
            # 检查文件扩展名
            allowed_extensions = {'.jpg', '.jpeg', '.png', '.bmp', '.gif'}
            file_ext = os.path.splitext(image_path)[1].lower()
            
            if file_ext not in allowed_extensions:
                return {
                    'is_valid': False,
                    'error': f'不支持的图片格式: {file_ext}，支持的格式: {", ".join(allowed_extensions)}'
                }
            
            # 尝试打开图片验证完整性
            try:
                with Image.open(image_path) as img:
                    img.verify()
            except Exception as e:
                return {
                    'is_valid': False,
                    'error': f'图片文件损坏或格式错误: {str(e)}'
                }
        
        return {
            'is_valid': True,
            'error': None
        }
        
    except Exception as e:
        return {
            'is_valid': False,
            'error': f'验证图片文件时出错: {str(e)}'
        }


def get_image_info(image_path: str) -> Dict[str, Any]:
    """
    获取图片基础信息，支持本地路径和MinIO URL
    
    Args:
        image_path (str): 图片文件路径或MinIO URL
        
    Returns:
        Dict[str, Any]: 图片信息
    """
    try:
        # 检查是否是MinIO URL
        if image_path.startswith('http://') or image_path.startswith('https://'):
            # 处理MinIO URL
            from urllib.parse import urlparse
            from io import BytesIO
            
            # 获取MinIO客户端
            minio_client = get_minio_client()
            if not minio_client:
                return {
                    'filename': os.path.basename(image_path),
                    'file_path': image_path,
                    'error': '无法连接到MinIO服务器'
                }
            
            # 提取对象键
            parsed_url = urlparse(image_path)
            path_parts = parsed_url.path.strip('/').split('/', 1)
            if len(path_parts) < 2:
                return {
                    'filename': os.path.basename(image_path),
                    'file_path': image_path,
                    'error': f'无效的MinIO URL格式: {image_path}'
                }
            
            object_key = path_parts[1]  # 跳过bucket名称
            
            # 从MinIO获取图片数据
            try:
                response = minio_client.get_object(Bucket=minio_bucket, Key=object_key)
                image_data = response['Body'].read()
                
                with Image.open(BytesIO(image_data)) as img:
                    return {
                        'filename': os.path.basename(parsed_url.path),
                        'file_path': image_path,
                        'file_size': len(image_data),
                        'file_size_mb': round(len(image_data) / (1024 * 1024), 2),
                        'dimensions': {
                            'width': img.width,
                            'height': img.height
                        },
                        'format': img.format,
                        'mode': img.mode,
                        'has_transparency': img.mode in ('RGBA', 'LA') or 'transparency' in img.info
                    }
            except Exception as minio_error:
                return {
                    'filename': os.path.basename(parsed_url.path),
                    'file_path': image_path,
                    'error': f'从MinIO获取图片失败: {str(minio_error)}'
                }
        else:
            # 处理本地文件路径
            with Image.open(image_path) as img:
                file_size = os.path.getsize(image_path)
                
                return {
                    'filename': os.path.basename(image_path),
                    'file_path': image_path,
                    'file_size': file_size,
                    'file_size_mb': round(file_size / (1024 * 1024), 2),
                    'dimensions': {
                        'width': img.width,
                        'height': img.height
                    },
                    'format': img.format,
                    'mode': img.mode,
                    'has_transparency': img.mode in ('RGBA', 'LA') or 'transparency' in img.info
                }
            
    except Exception as e:
        logging.error(f"获取图片信息失败: {str(e)}")
        return {
            'filename': os.path.basename(image_path),
            'file_path': image_path,
            'error': str(e)
        }


def _extract_business_card_info(image_path: str) -> Dict[str, Any]:
    """
    从名片图片中提取信息（模拟实现）
    
    Args:
        image_path (str): 名片图片路径
        
    Returns:
        Dict[str, Any]: 提取的名片信息
    """
    # TODO: 这里应该集成真实的OCR服务来识别名片信息
    # 目前返回模拟数据
    
    return {
        'name': '',  # 姓名
        'title': '',  # 职位
        'company': '',  # 公司
        'department': '',  # 部门
        'phone': '',  # 电话
        'mobile': '',  # 手机
        'email': '',  # 邮箱
        'address': '',  # 地址
        'website': '',  # 网站
        'fax': '',  # 传真
        'extracted_text': '',  # 原始识别文本
        'confidence_details': {
            'name': 0.0,
            'phone': 0.0,
            'email': 0.0,
            'company': 0.0
        }
    }


def _analyze_portrait_quality(image_path: str) -> Dict[str, Any]:
    """
    分析证件照质量（模拟实现）
    
    Args:
        image_path (str): 证件照图片路径
        
    Returns:
        Dict[str, Any]: 质量分析结果
    """
    try:
        with Image.open(image_path) as img:
            width, height = img.size
            
            # 基础质量检查
            quality_checks = {
                'resolution_check': {
                    'passed': width >= 300 and height >= 400,
                    'message': f'分辨率 {width}x{height}，建议至少300x400像素'
                },
                'aspect_ratio_check': {
                    'passed': 0.7 <= (height / width) <= 1.5,
                    'message': f'宽高比 {round(height/width, 2)}，建议在0.7-1.5之间'
                },
                'format_check': {
                    'passed': img.format in ['JPEG', 'PNG'],
                    'message': f'格式 {img.format}，建议使用JPEG或PNG格式'
                }
            }
            
            # 计算总体质量分数
            passed_checks = sum(1 for check in quality_checks.values() if check['passed'])
            quality_score = (passed_checks / len(quality_checks)) * 100
            
            return {
                'quality_score': quality_score,
                'quality_level': 'excellent' if quality_score >= 90 else 
                               'good' if quality_score >= 70 else 
                               'fair' if quality_score >= 50 else 'poor',
                'checks': quality_checks,
                'recommendations': _get_portrait_recommendations(quality_checks)
            }
            
    except Exception as e:
        logging.error(f"分析证件照质量失败: {str(e)}")
        return {
            'quality_score': 0,
            'quality_level': 'unknown',
            'error': str(e)
        }


def _get_portrait_recommendations(quality_checks: Dict[str, Dict]) -> List[str]:
    """
    根据质量检查结果生成改进建议
    
    Args:
        quality_checks (Dict[str, Dict]): 质量检查结果
        
    Returns:
        List[str]: 改进建议列表
    """
    recommendations = []
    
    if not quality_checks['resolution_check']['passed']:
        recommendations.append('建议使用更高分辨率的图片，至少300x400像素')
    
    if not quality_checks['aspect_ratio_check']['passed']:
        recommendations.append('建议调整图片宽高比，使其更符合证件照标准')
    
    if not quality_checks['format_check']['passed']:
        recommendations.append('建议使用JPEG或PNG格式')
    
    if not recommendations:
        recommendations.append('图片质量良好，符合基本要求')
    
    return recommendations


def convert_image_to_base64(image_path: str) -> Optional[str]:
    """
    将图片转换为Base64编码，支持本地路径和MinIO URL
    
    Args:
        image_path (str): 图片文件路径或MinIO URL
        
    Returns:
        Optional[str]: Base64编码字符串，失败时返回None
    """
    try:
        # 检查是否是MinIO URL
        if image_path.startswith('http://') or image_path.startswith('https://'):
            # 处理MinIO URL
            from urllib.parse import urlparse
            
            # 获取MinIO客户端
            minio_client = get_minio_client()
            if not minio_client:
                logging.error("无法连接到MinIO服务器")
                return None
            
            # 提取对象键
            parsed_url = urlparse(image_path)
            path_parts = parsed_url.path.strip('/').split('/', 1)
            if len(path_parts) < 2:
                logging.error(f"无效的MinIO URL格式: {image_path}")
                return None
            
            object_key = path_parts[1]  # 跳过bucket名称
            
            # 从MinIO获取图片数据
            try:
                response = minio_client.get_object(Bucket=minio_bucket, Key=object_key)
                image_data = response['Body'].read()
                encoded_string = base64.b64encode(image_data).decode('utf-8')
                return encoded_string
            except Exception as minio_error:
                logging.error(f"从MinIO获取图片失败: {str(minio_error)}")
                return None
        else:
            # 处理本地文件路径
            with open(image_path, 'rb') as image_file:
                encoded_string = base64.b64encode(image_file.read()).decode('utf-8')
                return encoded_string
            
    except Exception as e:
        logging.error(f"转换图片到Base64失败: {str(e)}")
        return None


def resize_image(image_path: str, max_width: int = 800, max_height: int = 600, 
                output_path: Optional[str] = None) -> Dict[str, Any]:
    """
    调整图片尺寸
    
    Args:
        image_path (str): 原始图片路径
        max_width (int): 最大宽度
        max_height (int): 最大高度
        output_path (str, optional): 输出路径，如果不指定则覆盖原文件
        
    Returns:
        Dict[str, Any]: 处理结果
    """
    try:
        with Image.open(image_path) as img:
            # 计算新尺寸，保持宽高比
            width, height = img.size
            ratio = min(max_width / width, max_height / height)
            
            if ratio < 1:  # 只有当图片超过最大尺寸时才调整
                new_width = int(width * ratio)
                new_height = int(height * ratio)
                
                resized_img = img.resize((new_width, new_height), Image.Resampling.LANCZOS)
                
                save_path = output_path or image_path
                resized_img.save(save_path, quality=95)
                
                return {
                    'success': True,
                    'original_size': (width, height),
                    'new_size': (new_width, new_height),
                    'compression_ratio': ratio,
                    'output_path': save_path
                }
            else:
                return {
                    'success': True,
                    'message': '图片尺寸已符合要求，无需调整',
                    'original_size': (width, height),
                    'output_path': image_path
                }
                
    except Exception as e:
        error_msg = f"调整图片尺寸失败: {str(e)}"
        logging.error(error_msg)
        
        return {
            'success': False,
            'error': error_msg
        }


def parse_table_image(image_path: str, task_id: Optional[str] = None) -> Dict[str, Any]:
    """
    解析包含表格的图片，提取人员信息
    
    Args:
        image_path (str): 表格图片路径
        task_id (str, optional): 关联的任务ID
        
    Returns:
        Dict[str, Any]: 解析结果
    """
    try:
        logging.info(f"开始解析表格图片: {image_path}")
        
        # 验证文件存在性和格式
        validation_result = validate_image_file(image_path)
        if not validation_result['is_valid']:
            return {
                'success': False,
                'error': validation_result['error'],
                'data': None
            }
        
        # 获取图片信息
        image_info = get_image_info(image_path)
        
        # 将图片转换为Base64进行千问模型调用
        base64_image = convert_image_to_base64(image_path)
        if not base64_image:
            return {
                'success': False,
                'error': '图片Base64转换失败',
                'data': None
            }
        
        # 调用千问模型解析表格
        try:
            table_data = parse_table_with_qwen(base64_image)
            logging.info("千问模型表格解析完成")
        except Exception as e:
            return {
                'success': False,
                'error': f"大模型解析失败: {str(e)}",
                'data': None
            }
        
        # 构建完整的解析结果
        result = {
            'success': True,
            'error': None,
            'data': {
                'extracted_data': table_data,
                'parse_time': get_east_asia_isoformat(),
                'image_info': image_info,
                'extraction_info': {
                    'extraction_method': 'Qwen-VL-Max',
                    'process_type': 'table',
                    'task_id': task_id
                }
            }
        }
        
        logging.info(f"表格图片解析完成: {image_path}")
        return result
        
    except Exception as e:
        error_msg = f"解析表格图片失败: {str(e)}"
        logging.error(error_msg, exc_info=True)
        
        return {
            'success': False,
            'error': error_msg,
            'data': None
        }


def parse_table_with_qwen(base64_image: str) -> List[Dict[str, Any]]:
    """
    使用阿里云千问大模型解析表格图片中的人员信息
    
    Args:
        base64_image (str): 图片的Base64编码
        
    Returns:
        List[Dict[str, Any]]: 解析的人员信息列表
    """
    # 阿里云 Qwen API 配置
    QWEN_API_KEY = os.environ.get('QWEN_API_KEY', 'sk-8f2320dafc9e4076968accdd8eebd8e9')
    
    try:
        # 初始化 OpenAI 客户端，配置为阿里云 API
        client = OpenAI(
            api_key=QWEN_API_KEY,
            base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
        )
        
        # 构建针对表格解析的专业提示语
        prompt = """你是表格信息提取专家。请仔细分析提供的图片中的表格内容，精确提取其中的人员信息。

## 提取要求
- 识别表格中的所有人员记录
- 区分中英文内容，分别提取
- 保持提取信息的原始格式（如大小写、标点）
- 对于无法识别或表格中不存在的信息，返回空字符串
- 表格中没有的信息，请不要猜测
- 如果表格中有多个人员，请全部提取

## 需提取的字段（每个人员一条记录）
1. 姓名 (name) - 中文姓名优先，如果只有英文则提取英文姓名
2. 工作单位 (work_unit) - 公司名称、酒店名称或机构名称
3. 职务头衔 (position) - 职位、头衔或职务名称
4. 手机号码 (mobile) - 手机号码，如有多个用逗号分隔
5. 邮箱 (email) - 电子邮箱地址

## 输出格式
请以严格的JSON数组格式返回结果，每个人员一个JSON对象。不要添加任何额外解释文字。

示例格式：
```json
[
  {
    "name": "张三",
    "work_unit": "北京万豪酒店",
    "position": "总经理",
    "mobile": "13800138000",
    "email": "zhangsan@marriott.com"
  },
  {
    "name": "李四",
    "work_unit": "上海希尔顿酒店", 
    "position": "市场总监",
    "mobile": "13900139000",
    "email": "lisi@hilton.com"
  }
]
```

如果表格中只有一个人员，也要返回数组格式：
```json
[
  {
    "name": "王五",
    "work_unit": "深圳凯悦酒店",
    "position": "人事经理",
    "mobile": "13700137000",
    "email": "wangwu@hyatt.com"
  }
]
```

请分析以下表格图片："""
        
        # 调用 Qwen VL Max API
        logging.info("发送表格图片请求到 Qwen VL Max 模型")
        completion = client.chat.completions.create(
            model="qwen-vl-max-latest",
            messages=[
                {
                    "role": "user",
                    "content": [
                        {"type": "text", "text": prompt},
                        {"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{base64_image}"}}
                    ]
                }
            ],
            temperature=0.1,  # 降低温度增加精确性
            response_format={"type": "json_object"}  # 要求输出JSON格式
        )
        
        # 解析响应
        response_content = completion.choices[0].message.content
        logging.info(f"成功从 Qwen 模型获取表格解析响应")
        
        # 直接解析 QWen 返回的 JSON 响应
        try:
            parsed_data = json.loads(response_content)
            logging.info("成功解析 Qwen 表格响应中的 JSON")
        except json.JSONDecodeError as e:
            error_msg = f"JSON 解析失败: {str(e)}"
            logging.error(error_msg)
            raise Exception(error_msg)
        
        # 确保返回的是数组格式
        if not isinstance(parsed_data, list):
            # 如果返回的不是数组，尝试提取数组或包装成数组
            if isinstance(parsed_data, dict):
                # 检查是否有数组字段
                for key, value in parsed_data.items():
                    if isinstance(value, list):
                        parsed_data = value
                        break
                else:
                    # 如果没有数组字段，将对象包装成数组
                    parsed_data = [parsed_data]
            else:
                parsed_data = []
        
        # 处理每个人员记录
        processed_data = []
        for person_data in parsed_data:
            if not isinstance(person_data, dict):
                continue
                
            # 确保所有必要字段存在
            required_fields = ['name', 'work_unit', 'position', 'mobile', 'email']
            for field in required_fields:
                if field not in person_data:
                    person_data[field] = ""
            
            # 创建职业轨迹记录
            career_entry = {
                "date": get_east_asia_date_str(),
                "hotel_en": '',
                "hotel_zh": person_data.get('work_unit', ''),
                "image_path": '',
                "source": 'table_extraction',
                "title_en": '',
                "title_zh": person_data.get('position', '')
            }
            
            # 创建隶属关系记录
            affiliation = []
            work_unit = person_data.get('work_unit', '')
            if work_unit:
                affiliation.append({
                    "company": work_unit,
                    "group": ""
                })
            
            # 将字段映射到标准格式，与任务解析结果.txt完全一致
            standardized_person = {
                "address_en": '',
                "address_zh": '',
                "affiliation": affiliation,
                "age": '',
                "birthday": '',
                "brand_group": '',
                "career_path": [career_entry],
                "email": person_data.get('email', ''),
                "hotel_en": '',
                "hotel_zh": person_data.get('work_unit', ''),
                "mobile": person_data.get('mobile', ''),
                "name_en": '',
                "name_zh": person_data.get('name', ''),
                "native_place": '',
                "phone": '',
                "postal_code_en": '',
                "postal_code_zh": '',
                "residence": '',
                "title_en": '',
                "title_zh": person_data.get('position', '')
            }
            
            processed_data.append(standardized_person)
            logging.info(f"处理人员记录: {person_data.get('name', 'Unknown')}")
        
        return processed_data
        
    except Exception as e:
        error_msg = f"Qwen VL Max 模型表格解析失败: {str(e)}"
        logging.error(error_msg, exc_info=True)
        raise Exception(error_msg)


def batch_process_images(image_paths: List[Any], process_type: str = 'table', task_id=None, task_type=None) -> Dict[str, Any]:
    """
    批量处理图片，从parse_task_repository表读取任务记录进行处理
    
    Args:
        image_paths (List[Any]): 图片路径列表（已废弃，现在从数据库读取）
        process_type (str): 处理类型，只支持 'table'
        task_id (str, optional): 任务ID，用于从数据库读取task_source
        task_type (str, optional): 任务类型
        
    Returns:
        Dict[str, Any]: 批量处理结果，格式与parse_result保持一致
    """
    try:
        # 根据task_id从parse_task_repository表读取记录
        if not task_id:
            return {
                'code': 400,
                'success': False,
                'message': '缺少task_id参数',
                'data': None
            }
        
        # 导入数据库模型
        from app.models.parse_models import ParseTaskRepository
        from app import db
        
        # 查询对应的任务记录
        task_record = ParseTaskRepository.query.get(task_id)
        if not task_record:
            return {
                'code': 404,
                'success': False,
                'message': f'未找到task_id为{task_id}的任务记录',
                'data': None
            }
        
        # 获取task_source作为需要处理的数据列表
        task_source = task_record.task_source
        if not task_source or not isinstance(task_source, list):
            return {
                'code': 400,
                'success': False,
                'message': 'task_source为空或格式不正确',
                'data': None
            }
        
        # 验证处理类型
        if process_type != 'table':
            return {
                'code': 400,
                'success': False,
                'message': 'process_type只支持table类型',
                'data': None
            }
        
        results = []
        success_count = 0
        failed_count = 0
        parsed_record_ids = []  # 收集成功解析的记录ID
        
        logging.info(f"开始批量处理图片，共 {len(task_source)} 个文件")
        
        # 逐一处理每个task_source元素
        for i, item in enumerate(task_source):
            try:
                # 检查parse_flag，只有值为1的才需要处理
                if not isinstance(item, dict) or item.get('parse_flag') != 1:
                    continue
                
                # 处理输入格式：支持字符串或字典格式
                image_path = item.get('minio_path')
                original_filename = item.get('original_filename', '')
                
                # 确保image_path是字符串类型
                if not image_path:
                    failed_count += 1
                    # 更新task_source中对应记录的状态
                    item['parse_flag'] = 1
                    item['status'] = '解析失败'
                    results.append({
                        "data": None,
                        "error": f"字典中缺少minio_path字段: {item}",
                        "filename": str(item),
                        "index": i,
                        "message": "图片路径格式无效",
                        "minio_path": "",
                        "object_key": "",
                        "success": False
                    })
                    logging.warning(f"第 {i+1} 个文件缺少minio_path字段")
                    continue
                elif not isinstance(image_path, str):
                    failed_count += 1
                    # 更新task_source中对应记录的状态
                    item['parse_flag'] = 1
                    item['status'] = '解析失败'
                    results.append({
                        "data": None,
                        "error": f"minio_path字段不是字符串类型: {type(image_path)}",
                        "filename": str(item),
                        "index": i,
                        "message": "图片路径格式无效",
                        "minio_path": "",
                        "object_key": "",
                        "success": False
                    })
                    logging.warning(f"第 {i+1} 个文件minio_path字段类型错误")
                    continue
                               
                logging.info(f"处理第 {i+1}/{len(image_paths)} 个文件: {image_path}")
                
                # 调用表格处理函数
                result = parse_table_image(image_path,task_id)
                
                if result.get('success', False):
                    # 提取表格数据并转换为多个人员记录
                    extracted_data = result.get('data', {}).get('extracted_data', [])
                    
                    if extracted_data and isinstance(extracted_data, list):
                        # 为每个人员创建一个结果记录
                        for person_idx, person_data in enumerate(extracted_data):
                            # 记录成功解析的人才信息到parsed_talents表
                            try:
                                from app.core.data_parse.parse_task import record_parsed_talent
                                
                                # 在记录到parsed_talents表之前，设置image_path和origin_source
                                person_data['image_path'] = image_path
                                
                                # 设置origin_source为JSON数组格式
                                current_date = get_east_asia_date_str()
                                origin_source_entry = {
                                    "task_type": "杂项",
                                    "minio_path": image_path,
                                    "source_date": current_date
                                }
                                person_data['origin_source'] = [origin_source_entry]
                                
                                # 更新career_path中记录的image_path字段
                                if person_data.get('career_path') and isinstance(person_data['career_path'], list):
                                    for career_entry in person_data['career_path']:
                                        if isinstance(career_entry, dict):
                                            career_entry['image_path'] = image_path
                                
                                record_result = record_parsed_talent(person_data, task_id, task_type)
                                if record_result.get('success'):
                                    # 收集成功解析的记录ID
                                    parsed_record = record_result.get('data', {})
                                    if parsed_record and 'id' in parsed_record:
                                        parsed_record_ids.append(str(parsed_record['id']))
                                    logging.info(f"成功记录人才信息到parsed_talents表: {person_data.get('name_zh', '')}")
                                else:
                                    logging.warning(f"记录人才信息失败: {record_result.get('message', '')}")
                            except Exception as record_error:
                                logging.error(f"调用record_parsed_talent函数失败: {str(record_error)}")
                            
                            success_count += 1
                            # 构建完整的MinIO URL路径
                            if original_filename:
                                filename = original_filename
                            elif isinstance(image_path, str) and image_path:
                                filename = os.path.basename(image_path)
                            else:
                                filename = f'table_file_{i}.jpg'
                            relative_path = f"misc_files/{filename}"
                            complete_minio_path = f"{minio_url}/{minio_bucket}/{relative_path}"
                            
                            results.append({
                                "data": person_data,
                                "error": None,
                                "filename": filename,
                                "index": len(results),  # 使用连续的索引
                                "message": "表格图片解析成功",
                                "minio_path": complete_minio_path,
                                "object_key": relative_path,
                                "success": True
                            })
                            logging.info(f"成功提取人员 {person_idx+1}: {person_data.get('name_zh', 'Unknown')}")
                        
                        # 更新task_source中对应记录的状态（成功处理）
                        item['parse_flag'] = 0
                        item['status'] = '解析成功'
                    else:
                        # 没有提取到有效数据
                        failed_count += 1
                        # 更新task_source中对应记录的状态
                        item['parse_flag'] = 1
                        item['status'] = '解析失败'
                        # 构建完整的MinIO URL路径
                        if original_filename:
                            filename = original_filename
                        elif isinstance(image_path, str) and image_path:
                            filename = os.path.basename(image_path)
                        else:
                            filename = f'table_file_{i}.jpg'
                        relative_path = f"misc_files/{filename}"
                        complete_minio_path = f"{minio_url}/{minio_bucket}/{relative_path}"
                        
                        results.append({
                            "data": None,
                            "error": "未从表格图片中提取到人员信息",
                            "filename": filename,
                            "index": i,
                            "message": "表格图片解析失败",
                            "minio_path": complete_minio_path,
                            "object_key": relative_path,
                            "success": False
                        })
                        logging.warning(f"第 {i+1} 个文件未提取到人员信息")
                else:
                    failed_count += 1
                    # 更新task_source中对应记录的状态
                    item['parse_flag'] = 1
                    item['status'] = '解析失败'
                    # 构建完整的MinIO URL路径
                    if original_filename:
                        filename = original_filename
                    elif isinstance(image_path, str) and image_path:
                        filename = os.path.basename(image_path)
                    else:
                        filename = f'table_file_{i}.jpg'
                    relative_path = f"misc_files/{filename}"
                    complete_minio_path = f"{minio_url}/{minio_bucket}/{relative_path}"
                    
                    results.append({
                        "data": None,
                        "error": result.get('error', '处理失败'),
                        "filename": filename,
                        "index": i,
                        "message": "表格图片解析失败",
                        "minio_path": complete_minio_path,
                        "object_key": relative_path,
                        "success": False
                    })
                    logging.error(f"处理第 {i+1} 个文件失败: {result.get('error', '未知错误')}")
                    
            except Exception as item_error:
                failed_count += 1
                error_msg = f"处理图片失败: {str(item_error)}"
                logging.error(error_msg, exc_info=True)
                # 更新task_source中对应记录的状态
                item['parse_flag'] = 1
                item['status'] = '解析失败'
                # 构建完整的MinIO URL路径
                if original_filename:
                    filename = original_filename
                elif isinstance(image_path, str) and image_path:
                    filename = os.path.basename(image_path)
                else:
                    filename = f'table_file_{i}.jpg'
                relative_path = f"misc_files/{filename}"
                complete_minio_path = f"{minio_url}/{minio_bucket}/{relative_path}"
                
                results.append({
                    "data": None,
                    "error": error_msg,
                    "filename": filename,
                    "index": i,
                    "message": "表格图片解析失败",
                    "minio_path": complete_minio_path,
                    "object_key": relative_path,
                    "success": False
                })
        
        # 根据处理结果更新task_status
        if failed_count == 0:
            task_status = '解析成功'
        elif success_count == 0:
            task_status = '解析失败'
        else:
            task_status = '部分解析成功'
        
        # 所有task_source记录处理完成后，将更新后的task_source和task_status保存到数据库
        try:
            task_record.task_source = task_source
            task_record.task_status = task_status
            task_record.parse_count = success_count
            task_record.parse_result = {
                'success_count': success_count,
                'failed_count': failed_count,
                'parsed_record_ids': parsed_record_ids,
                'processed_time': get_east_asia_isoformat()
            }
            db.session.commit()
            logging.info(f"成功更新task_id为{task_id}的任务记录，task_status={task_status}，处理成功{success_count}条，失败{failed_count}条")
        except Exception as update_error:
            logging.error(f"更新任务记录失败: {str(update_error)}")
            db.session.rollback()
        
        # 组装最终结果
        if failed_count == 0:
            return {
                'code': 200,
                'success': True,
                'message': f'批量处理完成，全部 {success_count} 个文件处理成功',
                'data': {
                    'success_count': success_count,
                    'failed_count': failed_count,
                    'parsed_record_ids': parsed_record_ids
                }
            }
        elif success_count == 0:
            return {
                'code': 500,
                'success': False,
                'message': f'批量处理失败，全部 {failed_count} 个文件处理失败',
                'data': {
                    'success_count': success_count,
                    'failed_count': failed_count,
                    'parsed_record_ids': parsed_record_ids
                }
            }
        else:
            return {
                'code': 206,  # Partial Content
                'success': True,
                'message': f'批量处理部分成功，成功 {success_count} 个，失败 {failed_count} 个',
                'data': {
                    'success_count': success_count,
                    'failed_count': failed_count,
                    'parsed_record_ids': parsed_record_ids
                }
            }
            
    except Exception as e:
        error_msg = f"批量处理图片失败: {str(e)}"
        logging.error(error_msg, exc_info=True)
        
        batch_result = {
            'summary': {
                'total_files': len(image_paths) if image_paths else 1,
                'success_count': 0,
                'failed_count': len(image_paths) if image_paths else 1,
                'success_rate': 0
            },
            'results': [],
            'processed_time': get_east_asia_isoformat()
        }
        
        return {
            'code': 500,
            'success': False,
            'message': error_msg,
            'data': batch_result
        } 