"""
API v1 通用模型
"""
import os
import uuid
from django.db import models
from django.contrib.auth import get_user_model
from django.db.models.fields.json import KeyTextTransform
from flower.common import ModelBase
from basic_info import models as basic_info_models

User = get_user_model()


def upload_file_path(instance, filename):
    """
    生成随机化的文件上传路径
    
    格式: uploads/YYYY/MM/DD/uuid.ext
    """
    # 获取文件扩展名
    ext = os.path.splitext(filename)[1].lower()
    # 生成随机文件名
    random_filename = f"{uuid.uuid4().hex}{ext}"
    # 返回完整路径
    from datetime import datetime
    now = datetime.now()
    return f"uploads/{now.year}/{now.month:02d}/{now.day:02d}/{random_filename}"


class UploadedFile(ModelBase):
    """
    通用文件上传记录
    
    用于存储无法归类到具体业务的文件上传记录
    """
    path = models.FileField(
        upload_to=upload_file_path,
        max_length=500,
        verbose_name='文件路径',
        help_text='文件存储路径，包含前缀、随机文件名和后缀'
    )
    owner = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        related_name='uploaded_files',
        verbose_name='上传者'
    )
    is_deleted = models.BooleanField(
        default=False,
        verbose_name='是否已删除',
        help_text='软删除标记'
    )
    original_filename = models.CharField(
        max_length=255,
        blank=True,
        verbose_name='原始文件名',
        help_text='用户上传时的原始文件名'
    )
    file_size = models.BigIntegerField(
        null=True,
        blank=True,
        verbose_name='文件大小(字节)'
    )
    content_type = models.CharField(
        max_length=100,
        blank=True,
        verbose_name='文件类型',
        help_text='MIME类型，如 image/jpeg'
    )
    
    class Meta:
        db_table = 'api_uploaded_file'
        verbose_name = '上传文件'
        verbose_name_plural = '上传文件'
        ordering = ['-created_at']
    
    def __str__(self):
        return f"{self.original_filename or self.path.name} (by {self.owner.username})"
    
    @property
    def file_url(self):
        """获取文件访问URL"""
        if self.path:
            return self.path.url
        return None


class DataSync(ModelBase):
    """记录外部数据同步的执行情况"""

    class TableName(models.TextChoices):
        PRODUCT = 'product', '产品'
        CUSTOMER = 'customer', '客户'
        PLATE_ORDER = 'plate_order', '开版（明道云）'
        PRINTING_EXTERNAL_RECORD = 'printing_external_record', '印染订单（外部 records）'
        MDY_PLATE_ORDER_STAGING_TIIA_UPLOAD = 'mdy_plate_order_staging_tiia_upload', '开版暂存-腾讯图库上传'

    table_name = models.CharField(max_length=50, choices=TableName.choices, verbose_name='同步目标')
    merchant = models.ForeignKey(
        basic_info_models.Merchant,
        on_delete=models.PROTECT,
        null=True,
        blank=True,
        related_name='data_sync_records',
        verbose_name='所属商户',
    )
    page_index = models.PositiveIntegerField(default=1, verbose_name='页码')
    page_size = models.PositiveIntegerField(default=100, verbose_name='每页数量')
    total_count = models.PositiveIntegerField(default=0, verbose_name='远端总数')
    synced_rows = models.PositiveIntegerField(default=0, verbose_name='本次同步数量')
    last_ctime = models.DateTimeField(null=True, blank=True, verbose_name='最新数据时间')
    last_rowid = models.CharField(max_length=64, blank=True, verbose_name='最新 RowID')
    note = models.CharField(max_length=255, blank=True, verbose_name='备注')

    class Meta:
        db_table = 'api_data_sync'
        verbose_name = '数据同步记录'
        verbose_name_plural = '数据同步记录'
        ordering = ['-created_at']

    def __str__(self):
        return f'{self.table_name} @ {self.created_at:%Y-%m-%d %H:%M:%S}'


class MDYPlateOrderStaging(ModelBase):
    """明道云"开版数据表"同步暂存表（不影响 printing.PlateOrder）。

    设计目标：
    - 与现有业务模型完全隔离，避免影响业务数据与流程
    - 仅保留 rowid 便于检索排查，其余信息全部落在 raw(JSON) 中
    - 随着同步深入再逐步"属性化"字段（从 raw 实时提取/映射）
    """

    mdy_rowid = models.CharField(
        max_length=64,
        unique=True,
        db_index=True,
        verbose_name='明道云 RowID',
        help_text='明道云行记录的 rowid（全局唯一）',
    )
    ctime = models.DateTimeField(
        null=True,
        blank=True,
        db_index=True,
        verbose_name='明道云创建时间',
        help_text='明道云系统字段 ctime（用于排序/增量定位）',
    )
    utime = models.DateTimeField(
        null=True,
        blank=True,
        db_index=True,
        verbose_name='明道云更新时间',
        help_text='明道云系统字段 utime（用于排序/增量定位）',
    )
    raw = models.JSONField(
        default=dict,
        blank=True,
        verbose_name='原始行数据',
        help_text='getFilterRows 返回的整行原始数据（包含各 controlId 字段）',
    )
    related = models.JSONField(
        default=list,
        blank=True,
        verbose_name='关联表数据',
        help_text='开版相关跨表数据（碾平 list[dict]），用于排查与后续属性化提取',
    )

    class Meta:
        db_table = 'api_mdy_plate_order_staging'
        verbose_name = '明道云开版暂存'
        verbose_name_plural = '明道云开版暂存'
        ordering = ['-created_at']
        indexes = [
            # 明道云字段：62d52f4b8d2972284492dd0e（开版表"订单id/设计编号"）
            # 用于在暂存表中按该字段快速检索
            models.Index(
                KeyTextTransform('62d52f4b8d2972284492dd0e', 'raw'),
                name='api_mdy_po_raw_id_idx',
            ),
        ]

    def __str__(self):
        return f'{self.mdy_rowid}'


class MDYPlateOrderStagingTiiaUploadFailure(ModelBase):
    """
    明道云开版暂存（MDYPlateOrderStaging）图片上传到腾讯云 TIIA 失败记录。

    说明：
    - 用于定时任务/批处理的失败落库，便于后续排查与补偿重试
    - 以 (run_date, mdy_rowid) 唯一，避免同一天重复刷屏
    """

    run_date = models.DateField(db_index=True, verbose_name='任务日期')
    mdy_rowid = models.CharField(max_length=64, db_index=True, verbose_name='明道云 RowID')
    staging_id = models.PositiveBigIntegerField(null=True, blank=True, db_index=True, verbose_name='暂存表ID')
    error = models.TextField(blank=True, verbose_name='错误摘要')
    details = models.JSONField(
        default=list,
        blank=True,
        verbose_name='错误详情',
        help_text='通常存储上传 service 返回的失败条目列表',
    )
    attempts = models.PositiveIntegerField(default=0, verbose_name='尝试次数')
    last_attempt_at = models.DateTimeField(null=True, blank=True, verbose_name='最后尝试时间')

    class Meta:
        db_table = 'api_mdy_plate_order_staging_tiia_upload_failure'
        verbose_name = '开版暂存图片上传失败记录'
        verbose_name_plural = '开版暂存图片上传失败记录'
        ordering = ['-created_at']
        constraints = [
            models.UniqueConstraint(
                fields=['run_date', 'mdy_rowid'],
                name='uniq_mdy_po_staging_tiia_fail_run_date_rowid',
            )
        ]

    def __str__(self):
        return f'{self.run_date} {self.mdy_rowid}'


class MDYPlateOrderStagingQiniuImageUploadAudit(ModelBase):
    """明道云开版暂存"开版图"迁移到七牛的逐图审计记录。"""

    class Status(models.TextChoices):
        PENDING = 'pending', '待处理'
        PROCESSING = 'processing', '处理中'
        SUCCESS = 'success', '成功'
        FAILED = 'failed', '失败'
        SKIPPED = 'skipped', '跳过'

    class Source(models.TextChoices):
        RAW_PLATE_IMAGES = 'raw_plate_images', 'raw.开版图'

    staging = models.ForeignKey(
        MDYPlateOrderStaging,
        on_delete=models.CASCADE,
        related_name='qiniu_image_upload_audits',
        verbose_name='开版暂存记录',
    )
    mdy_rowid = models.CharField(max_length=64, db_index=True, verbose_name='明道云 RowID')
    source = models.CharField(
        max_length=50,
        choices=Source.choices,
        default=Source.RAW_PLATE_IMAGES,
        verbose_name='图片来源',
    )
    attachment_index = models.PositiveIntegerField(verbose_name='附件序号')
    source_field = models.CharField(max_length=64, blank=True, verbose_name='原始 URL 字段')
    original_url = models.URLField(max_length=2048, verbose_name='原始图片 URL')
    original_host = models.CharField(max_length=255, blank=True, db_index=True, verbose_name='原始图片域名')
    qiniu_key = models.CharField(max_length=500, blank=True, verbose_name='七牛对象 Key')
    qiniu_url = models.URLField(max_length=2048, blank=True, verbose_name='七牛图片 URL')
    status = models.CharField(
        max_length=20,
        choices=Status.choices,
        default=Status.PENDING,
        db_index=True,
        verbose_name='上传状态',
    )
    attempts = models.PositiveIntegerField(default=0, verbose_name='尝试次数')
    error = models.TextField(blank=True, verbose_name='错误信息')
    file_size = models.PositiveBigIntegerField(null=True, blank=True, verbose_name='文件大小')
    content_type = models.CharField(max_length=100, blank=True, verbose_name='Content-Type')
    raw_attachment = models.JSONField(default=dict, blank=True, verbose_name='原始附件快照')
    started_at = models.DateTimeField(null=True, blank=True, verbose_name='开始处理时间')
    uploaded_at = models.DateTimeField(null=True, blank=True, verbose_name='上传成功时间')
    last_attempt_at = models.DateTimeField(null=True, blank=True, verbose_name='最后尝试时间')

    class Meta:
        db_table = 'api_mdy_plate_order_staging_qiniu_image_upload_audit'
        verbose_name = '开版暂存开版图七牛上传审计'
        verbose_name_plural = '开版暂存开版图七牛上传审计'
        ordering = ['-created_at']
        constraints = [
            models.UniqueConstraint(
                fields=['staging', 'source', 'attachment_index', 'source_field', 'original_url'],
                name='uniq_mdy_qiniu_staging_src_idx_url',
            )
        ]
        indexes = [
            models.Index(fields=['status', 'id'], name='mdy_qiniu_status_id_idx'),
            models.Index(fields=['original_url'], name='mdy_qiniu_orig_url_idx'),
            models.Index(fields=['staging', 'source'], name='mdy_qiniu_staging_src_idx'),
        ]

    def __str__(self):
        return f'{self.mdy_rowid}#{self.attachment_index} {self.status}'


class MDYPlateOrderStagingQiniuImageUploadState(ModelBase):
    """明道云开版暂存开版图上传任务的持久扫描游标。"""

    name = models.CharField(max_length=80, unique=True, verbose_name='任务名称')
    last_staging_id = models.PositiveBigIntegerField(default=0, verbose_name='已扫描到的暂存表ID')
    staging_finished = models.BooleanField(default=False, verbose_name='暂存表是否扫描完成')
    scanned_staging_rows = models.PositiveBigIntegerField(default=0, verbose_name='已扫描暂存行数')
    discovered_image_items = models.PositiveBigIntegerField(default=0, verbose_name='发现图片数')
    created_audit_rows = models.PositiveBigIntegerField(default=0, verbose_name='创建审计数')
    existing_audit_rows = models.PositiveBigIntegerField(default=0, verbose_name='已存在审计数')
    last_heartbeat_at = models.DateTimeField(null=True, blank=True, verbose_name='最后心跳时间')

    class Meta:
        db_table = 'api_mdy_plate_order_staging_qiniu_image_upload_state'
        verbose_name = '开版暂存开版图七牛上传状态'
        verbose_name_plural = '开版暂存开版图七牛上传状态'
        ordering = ['name']

    def __str__(self):
        return f'{self.name}: staging_id={self.last_staging_id}'


class PrintingExternalSyncFailure(ModelBase):
    """
    外部印染 records 同步失败记录。

    以外部 record.ID 为追踪主键，允许同一天重复失败时累加 attempts。
    """

    run_date = models.DateField(db_index=True, verbose_name='任务日期')
    external_record_id = models.PositiveBigIntegerField(db_index=True, verbose_name='外部记录ID')
    external_order_id = models.CharField(max_length=100, blank=True, verbose_name='外部订单编号')
    product_name = models.CharField(max_length=200, blank=True, verbose_name='外部产品名')
    error = models.TextField(blank=True, verbose_name='错误摘要')
    raw = models.JSONField(default=dict, blank=True, verbose_name='原始数据')
    attempts = models.PositiveIntegerField(default=0, verbose_name='尝试次数')
    last_attempt_at = models.DateTimeField(null=True, blank=True, verbose_name='最后尝试时间')

    class Meta:
        db_table = 'api_printing_external_sync_failure'
        verbose_name = '外部印染同步失败记录'
        verbose_name_plural = '外部印染同步失败记录'
        ordering = ['-created_at']
        constraints = [
            models.UniqueConstraint(
                fields=['run_date', 'external_record_id'],
                name='uniq_printing_ext_sync_fail_run_date_record',
            )
        ]

    def __str__(self):
        return f'{self.external_record_id} @ {self.run_date}'


class ApiAuditLog(models.Model):
    """API审计日志 - 记录创建/更新操作的历史现场

    用于保存特定模块的POST/PUT/PATCH请求，记录"创建/更新"操作的完整请求信息。
    通过Celery异步写入，避免影响API响应性能。
    """
    url = models.CharField(
        max_length=500,
        verbose_name='请求URL',
        help_text='完整的请求路径'
    )
    method = models.CharField(
        max_length=10,
        verbose_name='请求方法',
        help_text='HTTP方法，如POST、PUT、PATCH'
    )
    request_data = models.JSONField(
        default=dict,
        verbose_name='请求体数据',
        help_text='请求的body数据（JSON格式）'
    )
    query_params = models.JSONField(
        default=dict,
        verbose_name='查询参数',
        help_text='URL查询参数'
    )
    user_id = models.IntegerField(
        null=True,
        blank=True,
        db_index=True,
        verbose_name='用户ID',
        help_text='操作用户的ID'
    )
    username = models.CharField(
        max_length=150,
        blank=True,
        default='',
        verbose_name='用户名',
        help_text='操作用户的用户名快照'
    )
    response_status = models.IntegerField(
        null=True,
        blank=True,
        verbose_name='响应状态码',
        help_text='HTTP响应状态码'
    )
    created_at = models.DateTimeField(
        auto_now_add=True,
        db_index=True,
        verbose_name='创建时间'
    )
    
    class Meta:
        db_table = 'api_audit_log'
        verbose_name = 'API审计日志'
        verbose_name_plural = 'API审计日志'
        ordering = ['-created_at']
        indexes = [
            models.Index(fields=['user_id', 'created_at']),
            models.Index(fields=['url', 'created_at']),
        ]
    
    def __str__(self):
        return f'{self.method} {self.url} ({self.username or "anonymous"}) - {self.response_status}'
