#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
廠商缺貨通知系統 - 資料庫管理器
提供廠商缺貨資料的 CRUD 操作
"""

import os
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from datetime import datetime
from .vendor_models import Base, VendorStockout, VendorList, VendorEmail, EmailSendLog

# 導入日誌管理模組
from utils.logger_manager import SystemLogger

# 初始化日誌
sys_log = SystemLogger("VendorDatabase").get_logger()


class VendorDatabaseManager:
    """廠商缺貨系統資料庫管理器"""

    def __init__(self, db_path=None):
        """
        初始化資料庫連線。
        優先使用 PostgreSQL (透過 config.py 設定)，否則回退到 SQLite。

        Args:
            db_path: 資料庫檔案路徑 (僅 SQLite 模式使用)，若為 None 則使用預設路徑
        """
        # V-Fix (2026-01-23): 優先使用 config.py 的資料庫設定，與主 DatabaseManager 保持一致
        from config import DATABASE_PATH, DATABASE_TYPE

        if DATABASE_TYPE == 'postgresql':
            # PostgreSQL 模式 - 使用 config.py 的連線字串
            self.engine = create_engine(DATABASE_PATH, echo=False, pool_pre_ping=True)
            self.Session = sessionmaker(bind=self.engine)
            Base.metadata.create_all(self.engine)
            sys_log.info(f"[VendorDatabase] ✅ 使用 PostgreSQL 資料庫")
        else:
            # SQLite 模式 - 向後相容
            if db_path is None:
                base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
                db_path = os.path.join(base_dir, 'data', 'momo_database.db')

            sys_log.info(f"廠商缺貨系統資料庫連線初始化 | Path: {db_path}")

            # 確保資料夾存在
            os.makedirs(os.path.dirname(db_path), exist_ok=True)

            # 建立引擎與 Session
            self.engine = create_engine(f'sqlite:///{db_path}', echo=False)
            Base.metadata.create_all(self.engine)
            self.Session = sessionmaker(bind=self.engine)
            sys_log.info("[VendorDatabase] 使用 SQLite 資料庫")

        sys_log.info("✅ 廠商缺貨系統資料表已建立/更新")

    def get_session(self):
        """
        提供外部調用的 Session 實例。

        Returns:
            sqlalchemy.orm.Session: 資料庫 Session
        """
        return self.Session()

    # ==========================================
    # 廠商清單管理
    # ==========================================

    def add_vendor(self, vendor_code, vendor_name, is_active=True):
        """
        新增廠商

        Args:
            vendor_code: 廠商代碼
            vendor_name: 廠商名稱
            is_active: 是否啟用

        Returns:
            VendorList: 新增的廠商物件，若已存在則回傳 None
        """
        session = self.get_session()
        try:
            # 檢查是否已存在
            existing = session.query(VendorList).filter_by(vendor_code=vendor_code).first()
            if existing:
                sys_log.warning(f"廠商已存在 | 代碼: {vendor_code}")
                return None

            # 建立新廠商
            vendor = VendorList(
                vendor_code=vendor_code,
                vendor_name=vendor_name,
                is_active=is_active
            )
            session.add(vendor)
            session.commit()

            sys_log.info(f"✅ 新增廠商成功 | 代碼: {vendor_code} | 名稱: {vendor_name}")
            return vendor

        except Exception as e:
            session.rollback()
            sys_log.error(f"❌ 新增廠商失敗 | 代碼: {vendor_code} | 錯誤: {e}")
            return None
        finally:
            session.close()

    def get_vendor_by_code(self, vendor_code):
        """
        根據廠商代碼查詢廠商

        Args:
            vendor_code: 廠商代碼

        Returns:
            VendorList: 廠商物件，若不存在則回傳 None
        """
        session = self.get_session()
        try:
            vendor = session.query(VendorList).filter_by(vendor_code=vendor_code).first()
            return vendor
        finally:
            session.close()

    def get_all_vendors(self, active_only=True):
        """
        取得所有廠商清單

        Args:
            active_only: 是否只取得啟用中的廠商

        Returns:
            list: 廠商物件清單
        """
        session = self.get_session()
        try:
            query = session.query(VendorList)
            if active_only:
                query = query.filter_by(is_active=True)
            vendors = query.order_by(VendorList.vendor_code).all()
            return vendors
        finally:
            session.close()

    def update_vendor(self, vendor_code, vendor_name=None, is_active=None):
        """
        更新廠商資訊

        Args:
            vendor_code: 廠商代碼
            vendor_name: 廠商名稱 (可選)
            is_active: 是否啟用 (可選)

        Returns:
            bool: 是否更新成功
        """
        session = self.get_session()
        try:
            vendor = session.query(VendorList).filter_by(vendor_code=vendor_code).first()
            if not vendor:
                sys_log.warning(f"廠商不存在 | 代碼: {vendor_code}")
                return False

            # 更新欄位
            if vendor_name is not None:
                vendor.vendor_name = vendor_name
            if is_active is not None:
                vendor.is_active = is_active

            vendor.updated_at = datetime.now()
            session.commit()

            sys_log.info(f"✅ 更新廠商成功 | 代碼: {vendor_code}")
            return True

        except Exception as e:
            session.rollback()
            sys_log.error(f"❌ 更新廠商失敗 | 代碼: {vendor_code} | 錯誤: {e}")
            return False
        finally:
            session.close()

    def delete_vendor(self, vendor_code):
        """
        刪除廠商 (會連帶刪除相關的郵件與發送記錄)

        Args:
            vendor_code: 廠商代碼

        Returns:
            bool: 是否刪除成功
        """
        session = self.get_session()
        try:
            vendor = session.query(VendorList).filter_by(vendor_code=vendor_code).first()
            if not vendor:
                sys_log.warning(f"廠商不存在 | 代碼: {vendor_code}")
                return False

            session.delete(vendor)
            session.commit()

            sys_log.info(f"✅ 刪除廠商成功 | 代碼: {vendor_code}")
            return True

        except Exception as e:
            session.rollback()
            sys_log.error(f"❌ 刪除廠商失敗 | 代碼: {vendor_code} | 錯誤: {e}")
            return False
        finally:
            session.close()

    # ==========================================
    # 廠商郵件管理
    # ==========================================

    def add_vendor_email(self, vendor_code, email, contact_name=None,
                        email_type='primary', is_active=True, notes=None):
        """
        新增廠商郵件（自動去重）

        Args:
            vendor_code: 廠商代碼
            email: 郵件地址
            contact_name: 聯絡人姓名
            email_type: 郵件類型 (primary/cc/bcc)
            is_active: 是否啟用
            notes: 備註

        Returns:
            VendorEmail: 新增的郵件物件，若失敗或已存在則回傳 None
        """
        session = self.get_session()
        try:
            # 查詢廠商
            vendor = session.query(VendorList).filter_by(vendor_code=vendor_code).first()
            if not vendor:
                sys_log.warning(f"廠商不存在 | 代碼: {vendor_code}")
                return None

            # 檢查郵件是否已存在（去重）
            existing_email = session.query(VendorEmail).filter_by(
                vendor_id=vendor.id,
                email=email
            ).first()

            if existing_email:
                sys_log.debug(f"郵件已存在，跳過 | 廠商: {vendor_code} | 郵件: {email}")
                return None

            # 建立新郵件
            vendor_email = VendorEmail(
                vendor_id=vendor.id,
                email=email,
                contact_name=contact_name,
                email_type=email_type,
                is_active=is_active,
                notes=notes
            )
            session.add(vendor_email)
            session.commit()

            sys_log.info(f"✅ 新增廠商郵件成功 | 廠商: {vendor_code} | 郵件: {email}")
            return vendor_email

        except Exception as e:
            session.rollback()
            sys_log.error(f"❌ 新增廠商郵件失敗 | 廠商: {vendor_code} | 錯誤: {e}")
            return None
        finally:
            session.close()

    def get_vendor_emails(self, vendor_code, active_only=True):
        """
        取得廠商的所有郵件

        Args:
            vendor_code: 廠商代碼
            active_only: 是否只取得啟用中的郵件

        Returns:
            dict: 郵件清單，依類型分類 {'primary': [...], 'cc': [...], 'bcc': [...]}
        """
        session = self.get_session()
        try:
            vendor = session.query(VendorList).filter_by(vendor_code=vendor_code).first()
            if not vendor:
                return {'primary': [], 'cc': [], 'bcc': []}

            query = session.query(VendorEmail).filter_by(vendor_id=vendor.id)
            if active_only:
                query = query.filter_by(is_active=True)

            emails = query.all()

            # 依類型分類
            result = {'primary': [], 'cc': [], 'bcc': []}
            for email in emails:
                result[email.email_type].append(email)

            return result

        finally:
            session.close()

    def update_vendor_email(self, email_id, email=None, contact_name=None,
                           email_type=None, is_active=None, notes=None):
        """
        更新廠商郵件

        Args:
            email_id: 郵件 ID
            email: 郵件地址 (可選)
            contact_name: 聯絡人姓名 (可選)
            email_type: 郵件類型 (可選)
            is_active: 是否啟用 (可選)
            notes: 備註 (可選)

        Returns:
            bool: 是否更新成功
        """
        session = self.get_session()
        try:
            vendor_email = session.query(VendorEmail).filter_by(id=email_id).first()
            if not vendor_email:
                sys_log.warning(f"郵件不存在 | ID: {email_id}")
                return False

            # 更新欄位
            if email is not None:
                vendor_email.email = email
            if contact_name is not None:
                vendor_email.contact_name = contact_name
            if email_type is not None:
                vendor_email.email_type = email_type
            if is_active is not None:
                vendor_email.is_active = is_active
            if notes is not None:
                vendor_email.notes = notes

            vendor_email.updated_at = datetime.now()
            session.commit()

            sys_log.info(f"✅ 更新廠商郵件成功 | ID: {email_id}")
            return True

        except Exception as e:
            session.rollback()
            sys_log.error(f"❌ 更新廠商郵件失敗 | ID: {email_id} | 錯誤: {e}")
            return False
        finally:
            session.close()

    def delete_vendor_email(self, email_id):
        """
        刪除廠商郵件

        Args:
            email_id: 郵件 ID

        Returns:
            bool: 是否刪除成功
        """
        session = self.get_session()
        try:
            vendor_email = session.query(VendorEmail).filter_by(id=email_id).first()
            if not vendor_email:
                sys_log.warning(f"郵件不存在 | ID: {email_id}")
                return False

            session.delete(vendor_email)
            session.commit()

            sys_log.info(f"✅ 刪除廠商郵件成功 | ID: {email_id}")
            return True

        except Exception as e:
            session.rollback()
            sys_log.error(f"❌ 刪除廠商郵件失敗 | ID: {email_id} | 錯誤: {e}")
            return False
        finally:
            session.close()

    # ==========================================
    # 缺貨記錄管理
    # ==========================================

    def add_stockout_records(self, records_list, batch_id):
        """
        批次新增缺貨記錄 (用於 Excel 匯入)

        Args:
            records_list: 缺貨記錄清單 (dict list)
            batch_id: 批次編號

        Returns:
            tuple: (成功筆數, 失敗筆數, 重複筆數)
        """
        session = self.get_session()
        success_count = 0
        failed_count = 0
        duplicate_count = 0

        try:
            for record in records_list:
                try:
                    # 檢查是否為重複資料 (同一天 + 同廠商 + 同商品)
                    import_date = record.get('import_date', datetime.now().date())
                    vendor_code = record.get('vendor_code')
                    product_code = record.get('product_code')

                    existing = session.query(VendorStockout).filter_by(
                        import_date=import_date,
                        vendor_code=vendor_code,
                        product_code=product_code
                    ).first()

                    if existing:
                        # 標記為重複並更新計數
                        existing.duplicate_count += 1
                        existing.status = 'duplicate'
                        duplicate_count += 1
                        sys_log.debug(f"偵測到重複資料 | 廠商: {vendor_code} | 商品: {product_code}")
                        continue

                    # 建立新記錄
                    stockout = VendorStockout(
                        batch_id=batch_id,
                        import_date=import_date,
                        department=record.get('department'),
                        section=record.get('section'),
                        pm_name=record.get('pm_name'),
                        zone_id=record.get('zone_id'),
                        zone_name=record.get('zone_name'),
                        product_code=product_code,
                        product_name=record.get('product_name'),
                        product_spec=record.get('product_spec'),
                        borrow_transfer=record.get('borrow_transfer'),
                        sale_price=record.get('sale_price'),
                        cost_price=record.get('cost_price'),
                        vendor_code=vendor_code,
                        vendor_name=record.get('vendor_name'),
                        monthly_sales_qty=record.get('monthly_sales_qty'),
                        monthly_sales_amount=record.get('monthly_sales_amount'),
                        daily_avg_sales=record.get('daily_avg_sales'),
                        current_stock=record.get('current_stock'),
                        stockout_date=record.get('stockout_date'),
                        stockout_days=record.get('stockout_days'),
                        safe_stock_days=record.get('safe_stock_days'),
                        notes=record.get('notes')
                    )
                    session.add(stockout)
                    success_count += 1

                    # 每 100 筆提交一次
                    if success_count % 100 == 0:
                        session.commit()

                except Exception as e:
                    sys_log.error(f"❌ 新增缺貨記錄失敗 | 錯誤: {e}")
                    failed_count += 1
                    continue

            # 最後提交
            session.commit()
            sys_log.info(f"✅ 批次匯入完成 | 成功: {success_count} | 失敗: {failed_count} | 重複: {duplicate_count}")

            return success_count, failed_count, duplicate_count

        except Exception as e:
            session.rollback()
            sys_log.error(f"❌ 批次匯入失敗 | 錯誤: {e}")
            return success_count, failed_count, duplicate_count
        finally:
            session.close()

    def get_stockout_records(self, batch_id=None, vendor_code=None, status=None,
                            start_date=None, end_date=None, limit=None):
        """
        查詢缺貨記錄

        Args:
            batch_id: 批次編號 (可選)
            vendor_code: 廠商代碼 (可選)
            status: 狀態 (可選)
            start_date: 開始日期 (可選)
            end_date: 結束日期 (可選)
            limit: 限制筆數 (可選)

        Returns:
            list: 缺貨記錄清單
        """
        session = self.get_session()
        try:
            query = session.query(VendorStockout)

            # 篩選條件
            if batch_id:
                query = query.filter_by(batch_id=batch_id)
            if vendor_code:
                query = query.filter_by(vendor_code=vendor_code)
            if status:
                query = query.filter_by(status=status)
            if start_date:
                query = query.filter(VendorStockout.import_date >= start_date)
            if end_date:
                query = query.filter(VendorStockout.import_date <= end_date)

            # 排序與限制
            query = query.order_by(VendorStockout.import_date.desc())
            if limit:
                query = query.limit(limit)

            records = query.all()
            return records

        finally:
            session.close()

    def update_stockout_status(self, stockout_id, status, error_message=None,
                              sent_date=None, sent_by=None):
        """
        更新缺貨記錄狀態

        Args:
            stockout_id: 缺貨記錄 ID
            status: 狀態
            error_message: 錯誤訊息 (可選)
            sent_date: 發送時間 (可選)
            sent_by: 發送人員 (可選)

        Returns:
            bool: 是否更新成功
        """
        session = self.get_session()
        try:
            stockout = session.query(VendorStockout).filter_by(id=stockout_id).first()
            if not stockout:
                sys_log.warning(f"缺貨記錄不存在 | ID: {stockout_id}")
                return False

            stockout.status = status
            if error_message is not None:
                stockout.error_message = error_message
            if sent_date is not None:
                stockout.sent_date = sent_date
            if sent_by is not None:
                stockout.sent_by = sent_by

            stockout.updated_at = datetime.now()
            session.commit()

            sys_log.debug(f"更新缺貨記錄狀態 | ID: {stockout_id} | 狀態: {status}")
            return True

        except Exception as e:
            session.rollback()
            sys_log.error(f"❌ 更新缺貨記錄狀態失敗 | ID: {stockout_id} | 錯誤: {e}")
            return False
        finally:
            session.close()

    # ==========================================
    # 郵件發送記錄管理
    # ==========================================

    def add_email_log(self, vendor_code, batch_id, sender_email, recipient_email,
                     subject, product_count, cc_emails=None, bcc_emails=None,
                     attachment_filename=None, attachment_size=None, stockout_id=None):
        """
        新增郵件發送記錄

        Args:
            vendor_code: 廠商代碼
            batch_id: 發送批次編號
            sender_email: 寄件者郵件
            recipient_email: 收件者郵件
            subject: 郵件主旨
            product_count: 商品數量
            cc_emails: CC 郵件清單 (JSON 字串)
            bcc_emails: BCC 郵件清單 (JSON 字串)
            attachment_filename: 附件檔名
            attachment_size: 附件大小
            stockout_id: 缺貨記錄 ID

        Returns:
            EmailSendLog: 新增的記錄物件，若失敗則回傳 None
        """
        session = self.get_session()
        try:
            # 查詢廠商
            vendor = session.query(VendorList).filter_by(vendor_code=vendor_code).first()
            if not vendor:
                sys_log.warning(f"廠商不存在 | 代碼: {vendor_code}")
                return None

            # 建立記錄
            log = EmailSendLog(
                vendor_id=vendor.id,
                stockout_id=stockout_id,
                batch_id=batch_id,
                sender_email=sender_email,
                recipient_email=recipient_email,
                cc_emails=cc_emails,
                bcc_emails=bcc_emails,
                subject=subject,
                product_count=product_count,
                attachment_filename=attachment_filename,
                attachment_size=attachment_size,
                status='pending'
            )
            session.add(log)
            session.commit()

            sys_log.debug(f"新增郵件發送記錄 | 廠商: {vendor_code} | 收件者: {recipient_email}")
            return log

        except Exception as e:
            session.rollback()
            sys_log.error(f"❌ 新增郵件發送記錄失敗 | 廠商: {vendor_code} | 錯誤: {e}")
            return None
        finally:
            session.close()

    def update_email_log_status(self, log_id, status, error_message=None, sent_at=None):
        """
        更新郵件發送記錄狀態

        Args:
            log_id: 記錄 ID
            status: 狀態
            error_message: 錯誤訊息 (可選)
            sent_at: 發送時間 (可選)

        Returns:
            bool: 是否更新成功
        """
        session = self.get_session()
        try:
            log = session.query(EmailSendLog).filter_by(id=log_id).first()
            if not log:
                sys_log.warning(f"郵件發送記錄不存在 | ID: {log_id}")
                return False

            log.status = status
            if error_message is not None:
                log.error_message = error_message
            if sent_at is not None:
                log.sent_at = sent_at

            session.commit()

            sys_log.debug(f"更新郵件發送記錄狀態 | ID: {log_id} | 狀態: {status}")
            return True

        except Exception as e:
            session.rollback()
            sys_log.error(f"❌ 更新郵件發送記錄狀態失敗 | ID: {log_id} | 錯誤: {e}")
            return False
        finally:
            session.close()
