import hashlib
import math
import os
from io import BytesIO

import exifread
from apps.core.models.base import SEOMixin
from apps.core.models.url_style import UrlStyle
from apps.core.utils.hash import hash_id
from colorthief import ColorThief
from django.conf import settings
from django.contrib.auth.models import User
from django.db import models
from django.utils.translation import gettext_lazy as _
from imagekit.models import ProcessedImageField
from imagekit.processors import ResizeToFit

from .common import CreateCommon

EXIF_ENG_CN = {
    'Image ImageWidth': '图像宽度',
    'Image ImageLength': '图像长度',
    'Image ResolutionUnit': '分辨率单位',
    'Image Make': '制作',
    'Image Model': '模型',
    'Image Orientation': '方向',
    'Image DateTime': '日期时间',
    'Image YCbCrPositioning': 'y cb-cr定位',
    'Image ExifOffset': 'exif偏移',
    'GPS GPSLatitudeRef': 'gps纬度参考',
    'GPS GPSLatitude': 'gps纬度',
    'GPS GPSLongitudeRef': 'gps经度参考',
    'GPS GPSLongitude': 'gps经度',
    'GPS GPSAltitudeRef': 'gps高度参考',
    'GPS GPSAltitude': 'GPS高度',
    'GPS GPSTimeStamp': 'gps时间戳',
    'GPS GPSProcessingMethod': 'gps处理方法',
    'GPS GPSDate': 'gps日期',
    'Image GPSInfo': '全球定位系统信息',
    'Image XResolution': 'x分辨率',
    'Image YResolution': 'y分辨率',
    'Image Tag 0x9A00': '标签0x9a00',
    'Thumbnail JPEGInterchangeFormat': 'jpeg交换格式',
    'Thumbnail Orientation': '方向',
    'Thumbnail JPEGInterchangeFormatLength': 'jpeg交换格式长度',
    'Thumbnail Compression': '压缩',
    'Thumbnail ResolutionUnit': '分辨率单位',
    'Thumbnail XResolution': 'x分辨率',
    'Thumbnail YResolution': 'y分辨率',
    'Thumbnail ExifImageLength': 'exif图像长度',
    'Thumbnail ExifImageWidth': 'exif图像宽度',
    'EXIF Tag 0x9AAA': '标签0x9aaa',
    'EXIF ISOSpeedRatings': 'iso速度等级',
    'EXIF ExposureProgram': '曝光程序',
    'EXIF Tag 0xA661': '标签0x a661',
    'EXIF FNumber': 'f数',
    'EXIF ExposureTime': '曝光时间',
    'EXIF Tag 0x889A': '标签0x889a',
    'EXIF Tag 0x9999': '标签0x9999',
    'EXIF SensingMethod': '传感方法',
    'EXIF Tag 0x8895': '标签0x8895',
    'EXIF SubSecTimeDigitized': '亚秒时间数字化',
    'EXIF SubSecTimeOriginal': '亚秒级原始时间',
    'EXIF SubSecTime': '亚秒时间',
    'EXIF FocalLength': '焦距',
    'EXIF Flash': '闪光',
    'EXIF LightSource': '光源',
    'EXIF MeteringMode': '测光',
    'EXIF SceneCaptureType': '场景捕捉类型',
    'Interoperability InteroperabilityIndex': '互操作性互操作性指数',
    'Interoperability InteroperabilityVersion': '互操作性互操作性版本',
    'EXIF InteroperabilityOffset': '互操作性偏移',
    'EXIF FocalLengthIn35mmFilm': '35mm胶片焦距',
    'EXIF MaxApertureValue': '最大光圈值',
    'EXIF DateTimeDigitized': '数字化日期时间',
    'EXIF ExposureBiasValue': '曝光偏差值',
    'EXIF ExifImageLength': 'exif图像长度',
    'EXIF WhiteBalance': '白平衡',
    'EXIF DateTimeOriginal': '原始日期时间',
    'EXIF BrightnessValue': '亮度值',
    'EXIF ExifImageWidth': 'exif图像宽度',
    'EXIF ExposureMode': '曝光模式',
    'EXIF ApertureValue': '孔径值',
    'EXIF ComponentsConfiguration': '组件配置',
    'EXIF ColorSpace': '色空间',
    'EXIF SceneType': '场景类型',
    'EXIF ShutterSpeedValue': '快门速度值',
    'EXIF ExifVersion': 'Exif版本',
    'EXIF FlashPixVersion': 'flash pix版本',
    'EXIF Tag 0x9A00': '标签0x9a00',
}


class ImageGallery(SEOMixin, CreateCommon):
    """
    图片库模型
    继承自SEOMixin和CreateCommon基类
    """
    TARGET_DIR = 'content/gallery/processed'
    os.makedirs(os.path.join(settings.MEDIA_ROOT, TARGET_DIR), exist_ok=True)

    # print('验证图片库处理路径', os.path.join(settings.MEDIA_ROOT, TARGET_DIR))

    class LicenseChoices(models.TextChoices):
        CC_BY_NC_40 = 'CC BY-NC 4.0', _('知识共享-署名非商业4.0')
        CC_BY_SA_40 = 'CC BY-SA 4.0', _('知识共享-署名相同方式共享4.0')
        COPYRIGHT = 'COPYRIGHT', _('保留所有权利')
        PUBLIC_DOMAIN = 'PUBLIC', _('公有领域')

    class ImageSizePreset(models.TextChoices):
        ORIGINAL = 'origin', _('原始尺寸')
        LARGE = 'large', _('大图（1920px）')
        MEDIUM = 'medium', _('中图（1280px）')
        SMALL = 'small', _('小图（640px）')
        THUMBNAIL = 'thumbnail', _('缩略图（320px）')

    # 尺寸配置字典（宽度优先，高度设为极大值）
    SIZE_MAP = {
        ImageSizePreset.LARGE: (1920, 9999),
        ImageSizePreset.MEDIUM: (1280, 9999),
        ImageSizePreset.SMALL: (640, 9999),
        ImageSizePreset.THUMBNAIL: (320, 9999),
        ImageSizePreset.ORIGINAL: (None, None)  # 不缩放
    }

    image = models.ImageField(upload_to='content/gallery/%Y/%m/',
                              verbose_name=_('原始图片'),
                              max_length=500,
                              help_text=_('建议上传宽高比一致的图片'))
    alt_text = models.CharField(max_length=200,
                                blank=True,
                                verbose_name=_('图片ALT文本'),
                                help_text=_('用于无障碍访问和SEO优化'))
    category = models.ForeignKey(
        'content.category',
        on_delete=models.CASCADE,
        verbose_name=_('所属分类'),
        limit_choices_to={'content_type__model': 'imagegallery'},
        db_index=True  # 显式要求Django创建索引
    )
    related_tags = models.ManyToManyField('content.tag',
                                          blank=True,
                                          related_name="images",
                                          verbose_name="tags词",
                                          help_text="与模型 Keyword 相关联。")
    filtered_tags = models.ManyToManyField("content.Tag",
                                           blank=True,
                                           related_name="filtered_images",
                                           verbose_name="动态匹配标签",
                                           help_text="通过标签标题模糊匹配关联的标签")
    exif_info = models.JSONField(null=True,
                                 blank=True,
                                 verbose_name=_('EXIF信息'),
                                 help_text=_('自动提取的图片元数据'))
    color_palette = models.JSONField(null=True,
                                     blank=True,
                                     verbose_name=_('主色调'),
                                     help_text=_('自动提取的图片主色值'))
    aspect_ratio = models.CharField(max_length=20,
                                    blank=True,
                                    verbose_name=_('宽高比'),
                                    help_text=_('自动计算的宽高比例，如16:9'))
    is_cover = models.BooleanField(default=False,
                                   verbose_name=_('设为封面'),
                                   help_text=_('是否作为分类封面图片'))
    license = models.CharField(max_length=50,
                               choices=LicenseChoices.choices,
                               default=LicenseChoices.CC_BY_NC_40,
                               verbose_name=_('版权协议'))
    author = models.CharField(max_length=200,
                              verbose_name="作者",
                              blank=True,
                              default="")

    source = models.CharField(max_length=200,
                              verbose_name="来源",
                              default="本站原创",
                              help_text="请根据实际情况填写内容来源。")
    editor = models.ForeignKey(User,
                               on_delete=models.CASCADE,
                               verbose_name="内容编辑",
                               blank=True,
                               related_name="edited_images")
    file_hash = models.CharField(max_length=64, blank=True)

    class Meta:
        verbose_name = _('图片素材')
        verbose_name_plural = _('图片列表')
        ordering = ['-is_top', '-create_time']
        indexes = [
            # 复合索引（时间字段统一降序）
            models.Index(fields=['category', 'status', '-update_time'],
                         name='img_cate_status_utime_desc'),
            models.Index(fields=['category', 'status', '-create_time'],
                         name='img_cate_status_ctime_desc'),

            # 状态+降序时间组合
            models.Index(fields=['status', '-update_time'],
                         name='img_status_utime_desc'),
            models.Index(fields=['status', '-create_time'],
                         name='img_status_ctime_desc'),

            # 独立时间索引（显式降序）
            models.Index(fields=['-create_time'], name='img_ctime_desc'),
            models.Index(fields=['-update_time'], name='img_utime_desc'),

            # 业务索引（修正字段分隔符）
            models.Index(fields=['hits', 'status'], name='img_hits_status'),
            models.Index(fields=['category', 'hits', 'status'],
                         name='img_cate_hits_status'),
            models.Index(fields=['title'], name='img_title'),
            models.Index(fields=['category', '-update_time', '-id'],
                         name='img_cate_utime_id_desc'),
            models.Index(fields=['-update_time', '-id'],
                         name='img_utime_id_desc'),
            models.Index(fields=['category'], name='img_category_idx'),
        ]

    def __str__(self):
        return f"{self.title} ({self.image.width}x{self.image.height})"

    def save(self, *args, **kwargs):
        """智能存储方案整合EXIF解析与颜色分析"""
        # 第一阶段：基础文件存储
        if not self.pk or not self.image:
            return super().save(*args, **kwargs)

        # 第二阶段：增量更新检测
        if self.image:  # 确保有图片上传
            try:
                # 读取图片内容
                img_content = self.image.read()
                img_io = BytesIO(img_content)

                # 处理 EXIF 信息
                img_io.seek(0)  # 重置指针到文件开头
                tags = exifread.process_file(img_io, details=False)
                # 转换为可序列化的字典
                self.exif_info = {
                    tag: str(value)
                    for tag, value in tags.items()
                    if tag not in ('JPEGThumbnail', 'TIFFThumbnail',
                                   'Filename', 'EXIF MakerNote')
                }

                # 处理颜色调色板
                img_io.seek(0)
                color_thief = ColorThief(img_io)
                palette = color_thief.get_palette(color_count=5)
                self.color_palette = [
                    f'#{r:02x}{g:02x}{b:02x}' for r, g, b in palette
                ]

                # 处理宽高比
                img_io.seek(0)
                from PIL import Image as PILImage
                with PILImage.open(img_io) as img:
                    width, height = img.size
                    gcd = math.gcd(width, height)
                    self.aspect_ratio = f"{width//gcd}:{height//gcd}"

                # 计算文件哈希
                img_io.seek(0)
                self.file_hash = hashlib.sha256(img_content).hexdigest()

            except Exception as e:
                # 处理异常，例如记录日志或设置默认值
                pass
            finally:
                self.image.seek(0)  # 重置文件指针

        super().save(*args, **kwargs)

        # 最终保存更新
        return super().save(*args, **kwargs)

    def _calculate_file_hash(self):
        """文件变更检测哈希"""
        try:
            with self.image.open() as f:
                return hashlib.sha256(f.read()).hexdigest()
        except FileNotFoundError:
            return ''

    def get_absolute_url(self):
        '''
        变量为objects
        url_front=[('model', '模型路径（/model/123.html）'),
        ('slug', '单级Slug（/news/123.html）'),
        ('moreslug', '多级Slug（/news/sports/123.html）'),
        ('random', '随机字符（/jklfdsa/1.html）'),
        ('custom', '自定义路径（/mycategory/myarticle/1.shtml）')]    
        '''
        #无论前端怎么变量都为tag
        urlconfig = UrlStyle.get_solo()
        prefix = 'image'
        if urlconfig.url_mid == 'hash':
            url_mid = hash_id(self.id)
        else:
            url_mid = self.id
        return f'/{prefix}/{url_mid}{urlconfig.url_suffix}'

    def processed_upload_to(instance, size):
        return os.path.join(settings.MEDIA_ROOT, f'{instance.TARGET_DIR}',
                            f'{instance.id}_{size}.jpg')

    def img_path(instance, size):

        return os.path.join(f'{instance.TARGET_DIR}',
                            f'{instance.id}_{size}.jpg')
        # ORIGINAL = 'origin', _('原始尺寸')
        # LARGE = 'large', _('大图（1920px）')
        # MEDIUM = 'medium', _('中图（1280px）')
        # SMALL = 'small', _('小图（640px）')
        # THUMBNAIL = 'thumbnail', _('缩略图（320px）')
    @property
    def size_processor(self, size):
        width, height = self.get_size_params(size)
        return ProcessedImageField(
            upload_to=self.processed_upload_to(self, 'origin'),
            processors=[ResizeToFit((width, height or 99999))],
            format='JPEG')

    def get_size_params(self, size):
        """根据预设返回 (width, height) 元组"""
        return self.SIZE_MAP.get(size, (None, None))  # 默认不缩放
