from decimal import Decimal
import json

from django.db import models
from flower.common import ModelBase
from django.contrib.auth.models import User


# ==================== 常量定义 ====================
METER_TO_YARD_RATE = 0.9144
YARD_TO_METER_RATE = 1.09361


# ==================== 枚举类定义 ====================

class WareHouseModeEnum(models.IntegerChoices):
    """仓库出入库模式枚举"""
    RESTRICT_IN = 1, '严进宽出'
    RESTRICT_IN_OUT = 2, '严进严出'
    UNRESTRICTED = 3, '宽进宽出'


class WarehouseTypeEnum(models.IntegerChoices):
    """仓库类别枚举"""
    WHOLE = 1, '整仓'
    SCATTERED = 2, '散仓'


class MerchantTypeEnum(models.IntegerChoices):
    """商户类型枚举"""
    STORE = 1, '布行'
    FACTORY = 2, '印花厂'


class ProductUnitEnum(models.IntegerChoices):
    """产品单位枚举"""
    METER = 1, '米'
    YARD = 2, '码'
    KG = 3, '公斤'
    SEGMENT = 4, '段'


class EmployeeTypeEnum(models.TextChoices):
    """员工职位类型枚举"""
    PRINTER = '打纸', '打纸'
    ROLLING = '滚筒', '滚筒'
    WARE = '仓库', '仓库'
    DELIVERY = '送货', '送货'


class EmployeeStatusEnum(models.TextChoices):
    """员工状态枚举"""
    ACTIVE = '在职', '在职'
    INACTIVE = '离职', '离职'


class DeviceStatusEnum(models.TextChoices):
    """设备状态枚举"""
    ACTIVE = '使用中', '使用中'
    INACTIVE = '停用', '停用'
    MAINTENANCE = '维修中', '维修中'


class DeviceTypeEnum(models.TextChoices):
    """设备类型枚举"""
    ROLLING = '滚筒', '滚筒'
    PRINTER = '打印', '打印'


# ==================== 模型定义 ====================


class FrontendPageTypeEnum(models.TextChoices):
    """前端页面类型枚举"""
    MAIN = 'main', '主菜单'
    SUB = 'sub', '子菜单'


class FrontendPage(ModelBase):
    """
    前端页面/菜单项
    
    用于管理前端可见页面，与员工岗位关联实现权限控制。
    数据来源：docs/menu_keys.json，通过 sync_frontend_pages 命令同步。
    """
    id = models.BigAutoField(primary_key=True)
    key = models.CharField(
        max_length=100,
        unique=True,
        db_index=True,
        verbose_name='页面唯一标识',
        help_text='前端路由 key，如 plate-order-kanban'
    )
    label = models.CharField(max_length=100, verbose_name='页面名称')
    page_type = models.CharField(
        max_length=10,
        choices=FrontendPageTypeEnum.choices,
        default=FrontendPageTypeEnum.SUB,
        verbose_name='页面类型'
    )
    parent = models.ForeignKey(
        'self',
        on_delete=models.CASCADE,
        null=True,
        blank=True,
        related_name='children',
        verbose_name='父级菜单'
    )
    sort_order = models.IntegerField(default=0, verbose_name='排序')
    is_active = models.BooleanField(default=True, verbose_name='是否启用')

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

    class Meta:
        verbose_name = '前端页面'
        verbose_name_plural = '前端页面'
        ordering = ['sort_order', 'id']


class EmployeeType(ModelBase):
    """员工职位类型"""
    id = models.BigAutoField(primary_key=True)
    merchant = models.ForeignKey('Merchant', on_delete=models.PROTECT, related_name='employee_types', verbose_name='所属商户')
    title = models.CharField(max_length=50, verbose_name='职位名称')
    description = models.TextField(blank=True, null=True, verbose_name='职位描述')
    reverse = models.CharField(max_length=100, blank=True, null=True, verbose_name='预留字段')
    visible_pages = models.ManyToManyField(
        'FrontendPage',
        blank=True,
        related_name='employee_types',
        verbose_name='可见页面',
        help_text='授予主菜单将自动包含其所有子菜单'
    )

    def __str__(self):
        return self.title

    class Meta:
        verbose_name = '员工职位类型'
        verbose_name_plural = '员工职位类型'
        unique_together = ('merchant', 'title')


class QuickInput(ModelBase):
    id = models.BigAutoField(primary_key=True)
    name = models.CharField(max_length=100, verbose_name='名')
    value = models.CharField(max_length=200, verbose_name='值')
    group = models.CharField(verbose_name='组')

    def __str__(self):
        return f'{self.group}-{self.name}'

    class Meta:
        verbose_name = '快捷输入'
        verbose_name_plural = '快捷输入'
        unique_together = ('name', 'group')


class Merchant(ModelBase):
    id = models.BigAutoField(primary_key=True)
    name = models.CharField(max_length=100, verbose_name='商户名称')
    type = models.IntegerField(choices=MerchantTypeEnum.choices, verbose_name='商户类型')
    area = models.CharField(max_length=100, blank=True, null=True, verbose_name='地区')
    email = models.EmailField(blank=True, null=True, verbose_name='电子邮箱')
    mobile = models.CharField(max_length=20, blank=True, null=True, verbose_name='手机')
    contact = models.TextField(blank=True, null=True, verbose_name='联系人')
    auto_complete_stock_change = models.BooleanField(
        default=False, 
        verbose_name='自动确认库存变动',
    )
    description = models.TextField(blank=True, null=True, verbose_name='备注描述')

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = '商户资料'
        verbose_name_plural = '商户资料'


class VehicleType(ModelBase):
    id = models.BigAutoField(primary_key=True)
    merchant = models.ForeignKey('Merchant', on_delete=models.PROTECT, related_name='vehicle_types', verbose_name='所属商户')
    name = models.CharField(max_length=50, verbose_name='车辆类型名称')
    description = models.TextField(blank=True, null=True, verbose_name='备注描述')

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = '车辆类型'
        verbose_name_plural = '车辆类型'


class WareHouse(ModelBase):
    id = models.BigAutoField(primary_key=True)
    merchant = models.ForeignKey('Merchant', on_delete=models.PROTECT, related_name='warehouses', verbose_name='所属商户')
    name = models.CharField(max_length=100, verbose_name='仓库名称')
    location = models.CharField(max_length=200, blank=True, null=True, verbose_name='仓库地址')
    type = models.IntegerField(
        choices=WarehouseTypeEnum.choices,
        default=WarehouseTypeEnum.WHOLE,
        verbose_name='仓库类别',
    )
    mode = models.IntegerField(
        choices=WareHouseModeEnum.choices,
        default=WareHouseModeEnum.RESTRICT_IN,
        verbose_name='出入库模式',
    )
    contact = models.CharField(max_length=100, blank=True, null=True, verbose_name='联系人')
    mobile = models.CharField(max_length=20, blank=True, null=True, verbose_name='手机')
    area = models.CharField(max_length=100, blank=True, null=True, verbose_name='地区')
    description = models.TextField(blank=True, null=True, verbose_name='备注描述')

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = '仓库资料'
        verbose_name_plural = '仓库资料'


class Supplier(ModelBase):
    id = models.BigAutoField(primary_key=True)
    merchant = models.ForeignKey('Merchant', on_delete=models.PROTECT, related_name='suppliers', verbose_name='所属商户')
    name = models.CharField(max_length=100, verbose_name='供应商名称')
    area = models.CharField(max_length=100, blank=True, null=True, verbose_name='地区')
    email = models.EmailField(blank=True, null=True, verbose_name='电子邮箱')
    mobile = models.CharField(max_length=20, blank=True, null=True, verbose_name='手机')
    contact = models.TextField(blank=True, null=True, verbose_name='联系人')
    description = models.TextField(blank=True, null=True, verbose_name='备注描述')

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = '供应商'
        verbose_name_plural = '供应商'


class BankAccount(ModelBase):
    id = models.BigAutoField(primary_key=True)
    merchant = models.ForeignKey('Merchant', on_delete=models.PROTECT, related_name='bank_accounts', verbose_name='所属商户')
    name = models.CharField(max_length=100, verbose_name='名称')
    auto_number = models.CharField(max_length=50, verbose_name='自动编号')
    description = models.TextField(blank=True, null=True, verbose_name='备注描述')
    attachment = models.FileField(upload_to='bank_accounts/', blank=True, null=True, verbose_name='附件')

    def __str__(self):
        return f'{self.name} - {self.auto_number}'

    class Meta:
        verbose_name = '银行账户'
        verbose_name_plural = '银行账户'


class ProductCategory(ModelBase):
    id = models.BigAutoField(primary_key=True)
    merchant = models.ForeignKey('Merchant', on_delete=models.PROTECT, related_name='product_categories', verbose_name='所属商户')
    name = models.CharField(max_length=100, verbose_name='类别名称')
    description = models.TextField(blank=True, null=True, verbose_name='类别描述')
    product_prefix = models.CharField(max_length=5, verbose_name='产品编号前缀')

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = '产品类别'
        verbose_name_plural = '产品类别'


class Product(ModelBase):
    id = models.BigAutoField(primary_key=True)
    merchant = models.ForeignKey('Merchant', on_delete=models.PROTECT, verbose_name='所属商户')
    category = models.ForeignKey(
        ProductCategory,
        on_delete=models.PROTECT,
        related_name='products',
        verbose_name='产品类别',
    )
    name = models.CharField(max_length=100, verbose_name='产品名')
    human_id = models.CharField(max_length=100, verbose_name='产品编号', blank=True)
    color = models.CharField(max_length=50, blank=True, null=True, verbose_name='颜色')
    width_size = models.DecimalField(max_digits=10, decimal_places=2, blank=True, null=True, verbose_name='宽幅')
    pieces = models.IntegerField(blank=True, null=True, verbose_name='件数')
    segment_size = models.DecimalField(blank=True, null=True, verbose_name='一段尺寸', decimal_places=2, max_digits=8)
    single_price_in = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        verbose_name='参考进价',
        blank=True,
        null=True,
    )
    single_price_out = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        verbose_name='参考售价',
        blank=True,
        null=True,
    )
    unit = models.IntegerField(
        choices=ProductUnitEnum.choices,
        default=ProductUnitEnum.METER,
        verbose_name='单位',
    )
    spec = models.CharField(max_length=100, blank=True, null=True, verbose_name='规格')
    description = models.TextField(blank=True, null=True, verbose_name='备注描述')
    image = models.ImageField(
        upload_to='product_images/', 
        blank=True, 
        null=True, 
        verbose_name='产品图片',
    )
    mdy_image_url = models.URLField(
        max_length=500,
        blank=True,
        null=True,
        verbose_name='明道云图片URL',
        help_text='来自明道云的图片链接',
    )
    minimum_quantity = models.IntegerField(null=True, blank=True, verbose_name='最低库存量')
    transform_rate = models.DecimalField(
        max_digits=10,
        decimal_places=4,
        blank=True,
        null=True,
        verbose_name='公斤转换率',
    )
    from_mdy = models.BooleanField(
        default=False,
        verbose_name='是否来自明道云同步',
        help_text='标记该产品是否通过明道云接口同步',
    )

    def get_primary_image_url(self):
        """
        优先返回 mdy_image_url；若为空则尝试从 description JSON 中提取 original_file_full_path。
        """
        if self.mdy_image_url:
            return self.mdy_image_url

        if not self.description:
            return None

        try:
            payload = json.loads(self.description) if isinstance(self.description, str) else self.description
        except (TypeError, ValueError, json.JSONDecodeError):
            return None

        if isinstance(payload, dict):
            items = [payload]
        elif isinstance(payload, list):
            items = payload
        else:
            return None

        for item in items:
            if not isinstance(item, dict):
                continue
            url = item.get('original_file_full_path') or item.get('DownloadUrl')
            if url:
                return url
        return None

    def __str__(self):
        return self.name

    def save(
            self,
            *args,
            force_insert=False,
            force_update=False,
            using=None,
            update_fields=None,
    ):
        super().save(
            *args,
            force_insert=force_insert,
            force_update=force_update,
            using=using,
            update_fields=update_fields,
        )
        # Generate human_id if not set after saving to get the ID
        if not self.human_id and self.category:
            self.human_id = f'{self.category.product_prefix}{self.id:05d}'
            super().save(
                *args,
                force_insert=False,
                force_update=False,
                using=using,
                update_fields=['human_id'],
            )

    class Meta:
        verbose_name = '产品资料'
        verbose_name_plural = '产品资料'


class Customer(ModelBase):
    id = models.BigAutoField(primary_key=True)
    merchant = models.ForeignKey('Merchant', on_delete=models.PROTECT, related_name='customers', verbose_name='所属商户')
    name = models.CharField(max_length=100, verbose_name='客户名称')
    visible_employees = models.ManyToManyField(
        'Employee', 
        blank=True, 
        related_name='visible_customers',
        verbose_name='可见该客户的员工',
    )
    created_by = models.ForeignKey(
        'Employee', 
        on_delete=models.PROTECT, 
        related_name='created_customers',
        null=True,
        verbose_name='创建者',
    )
    mobile = models.CharField(max_length=20, null=True, blank=True, verbose_name='手机')
    area = models.CharField(max_length=100, blank=True, null=True, verbose_name='地区')
    email = models.EmailField(blank=True, null=True, verbose_name='电子邮箱')
    contact = models.CharField(blank=True, null=True, verbose_name='联系人')
    description = models.TextField(blank=True, null=True, verbose_name='备注描述')
    mdy_uid = models.CharField(
        max_length=100,
        unique=True,
        null=True,
        blank=True,
        verbose_name='明道云UID',
        help_text='对应明道云记录的唯一标识',
    )
    from_mdy = models.BooleanField(
        default=False,
        verbose_name='是否来自明道云同步',
        help_text='标记该客户是否通过明道云接口同步',
    )

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = '客户资料'
        verbose_name_plural = '客户资料'
        constraints = [
            models.UniqueConstraint(
                fields=['merchant', 'name'],
                name='uniq_customer_merchant_name',
            ),
        ]
        permissions = [
            ('view_all_customers', '查看所有客户资料'),
        ]


class Employee(ModelBase):
    id = models.BigAutoField(primary_key=True)
    merchant = models.ForeignKey('Merchant', on_delete=models.PROTECT, related_name='employees', verbose_name='所属商户')
    sys_user = models.OneToOneField(
        User,
        on_delete=models.PROTECT,
        related_name='employee',
        null=True,
        blank=True,
        verbose_name='系统用户',
    )
    name = models.CharField(max_length=100, verbose_name='员工姓名')
    position = models.ForeignKey(
        'EmployeeType',
        on_delete=models.PROTECT,
        related_name='employees',
        null=True,
        blank=True,
        verbose_name='职位',
    )
    mobile = models.CharField(max_length=20, blank=True, null=True, verbose_name='手机')
    area = models.CharField(max_length=100, blank=True, null=True, verbose_name='地区')
    description = models.TextField(blank=True, null=True, verbose_name='备注描述')
    status = models.CharField(
        max_length=20,
        choices=EmployeeStatusEnum.choices,
        default=EmployeeStatusEnum.ACTIVE,
        verbose_name='员工状态',
    )
    wecom_user_id = models.CharField(
        max_length=128,
        unique=True,
        null=True,
        blank=True,
        verbose_name='企业微信用户ID',
        help_text='企业微信 OAuth2 返回的 user_id',
    )

    @property
    def job_type(self) -> str:
        """
        返回职位名称（向后兼容）
        
        如果有关联的职位类型，返回其 title，否则返回空字符串
        """
        if self.position:
            return self.position.title
        return ''

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = '员工资料'
        verbose_name_plural = '员工资料'


class UserProfile(ModelBase):
    id = models.BigAutoField(primary_key=True)
    user = models.OneToOneField(
        User,
        on_delete=models.CASCADE,
        related_name='profile',
        verbose_name='关联用户',
    )
    merchant = models.ForeignKey(
        'Merchant',
        on_delete=models.PROTECT,
        related_name='user_profiles',
        verbose_name='所属商户',
    )
    description = models.TextField(blank=True, null=True, verbose_name='备注描述')

    def __str__(self):
        return f"{self.user.username}'s Profile"

    class Meta:
        verbose_name = '用户资料扩展'
        verbose_name_plural = '用户资料扩展'


class DeviceInfo(ModelBase):
    id = models.BigAutoField(primary_key=True)
    merchant = models.ForeignKey('Merchant', on_delete=models.PROTECT, related_name='devices', verbose_name='所属商户')
    name = models.CharField(max_length=100, verbose_name='设备名称')
    type = models.CharField(
        max_length=20,
        choices=DeviceTypeEnum.choices,
        default=DeviceTypeEnum.ROLLING,
        verbose_name='设备类型',
    )
    status = models.CharField(
        max_length=20,
        choices=DeviceStatusEnum.choices,
        default=DeviceStatusEnum.ACTIVE,
        verbose_name='设备状态',
    )
    start_working_at = models.DateField(blank=True, null=True, verbose_name='开始服役日期')
    stop_working_at = models.DateField(blank=True, null=True, verbose_name='停止服役日期')
    is_occupied = models.BooleanField(default=False, verbose_name='是否被占用')
    description = models.TextField(blank=True, null=True, verbose_name='备注描述')

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = '设备资料'
        verbose_name_plural = '设备资料'


class VehicleTransportRecord(ModelBase):
    id = models.BigAutoField(primary_key=True)
    merchant = models.ForeignKey('Merchant', on_delete=models.PROTECT, related_name='vehicle_transport_records', verbose_name='所属商户')
    vehicle_type = models.ForeignKey(
        VehicleType,
        on_delete=models.PROTECT,
        related_name='vehicles',
        verbose_name='车次',
    )
    driver_name = models.CharField(max_length=100, verbose_name='司机姓名')
    contact_number = models.CharField(max_length=20, blank=True, null=True, verbose_name='联系电话')
    license_plate = models.CharField(max_length=20, verbose_name='车牌号码', null=True, blank=True)
    delivery_date = models.DateField(verbose_name='送货日期')

    def __str__(self):
        return f'{self.vehicle_type}-{self.driver_name}-{self.delivery_date}'

    class Meta:
        verbose_name = '司机车次'
        verbose_name_plural = '司机车次'


class TransportVehicle(ModelBase):
    id = models.BigAutoField(primary_key=True)
    merchant = models.ForeignKey('Merchant', on_delete=models.PROTECT, related_name='transport_vehicles', verbose_name='所属商户')
    name = models.CharField(max_length=100, verbose_name='车辆名称')
    license_plate = models.CharField(max_length=20, verbose_name='车牌号码')

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

    class Meta:
        verbose_name = '运输车辆'
        verbose_name_plural = '运输车辆'
        unique_together = ('merchant', 'license_plate')


class TransportVehicleMaterialCapacity(ModelBase):
    id = models.BigAutoField(primary_key=True)
    merchant = models.ForeignKey('Merchant', on_delete=models.PROTECT, related_name='transport_vehicle_material_capacities', verbose_name='所属商户')
    transport_vehicle = models.ForeignKey(
        TransportVehicle,
        on_delete=models.CASCADE,
        related_name='material_capacities',
        verbose_name='运输车辆',
    )
    material_name = models.CharField(max_length=100, verbose_name='物料名')
    capacity = models.PositiveIntegerField(verbose_name='容量（条）')

    def __str__(self):
        return f'{self.transport_vehicle.name}-{self.material_name}:{self.capacity}'

    class Meta:
        verbose_name = '运输车辆物料容量'
        verbose_name_plural = '运输车辆物料容量'
        unique_together = ('transport_vehicle', 'material_name')


class MerchantSettingTypeEnum(models.TextChoices):
    """商户设置类型枚举"""
    STR = 'str', '字符串'
    INT = 'int', '整数'
    FLOAT = 'float', '浮点数'
    BOOL = 'bool', '布尔值'


class MerchantSetting(ModelBase):
    id = models.BigAutoField(primary_key=True)
    merchant = models.ForeignKey('Merchant', on_delete=models.PROTECT, related_name='settings', verbose_name='所属商户')
    key = models.CharField(max_length=100, verbose_name='设置项')
    type = models.CharField(
        max_length=20,
        choices=MerchantSettingTypeEnum.choices,
        default=MerchantSettingTypeEnum.STR,
        verbose_name='设置类型',
    )
    val_str = models.CharField(max_length=100, null=True, blank=True, verbose_name='设置值(字符串)')
    val_int = models.IntegerField(null=True, blank=True, verbose_name='设置值(整数)')
    val_float = models.FloatField(null=True, blank=True, verbose_name='设置值(浮点数)')
    val_bool = models.BooleanField(null=True, blank=True, verbose_name='设置值(布尔值)')
    description = models.TextField(blank=True, null=True, verbose_name='备注')

    @property
    def value(self):
        if self.type == MerchantSettingTypeEnum.STR:
            return self.val_str
        elif self.type == MerchantSettingTypeEnum.INT:
            return self.val_int
        elif self.type == MerchantSettingTypeEnum.FLOAT:
            return self.val_float
        elif self.type == MerchantSettingTypeEnum.BOOL:
            return self.val_bool
        raise ValueError(f'Invalid setting type: {self.type}')

    def __str__(self):
        return f'{self.merchant.name} - {self.key}'

    class Meta:
        verbose_name = '商户设置'
        verbose_name_plural = '商户设置'


class MerchantSettingKeyEnum(models.TextChoices):
    """商户设置项枚举"""
    AUTO_CREATE_STOCK_CHANGE_TASKS = 'auto_create_stock_change_tasks', '自动创建出入库记录任务'
