#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
廠商缺貨查詢服務

集中管理 Vendor V2 頁面所需的統計、篩選、分頁與排序查詢，讓
routes/vendor_routes.py 保持 thin Blueprint。
"""

from sqlalchemy import desc, func, or_

from database.vendor_models import EmailSendLog, VendorEmail, VendorList, VendorStockout


def _pending_stockout_filter():
    return or_(
        VendorStockout.status == 'pending',
        VendorStockout.status.is_(None)
    )


def get_vendor_dashboard_stats(vendor_db):
    """彙整廠商缺貨首頁 V2 所需的真實資料庫統計。"""
    session = vendor_db.get_session()
    try:
        total_stockouts = session.query(VendorStockout).count()
        pending_stockouts = session.query(VendorStockout).filter(_pending_stockout_filter()).count()
        sent_stockouts = session.query(VendorStockout).filter(VendorStockout.status == 'sent').count()
        failed_stockouts = session.query(VendorStockout).filter(VendorStockout.status == 'failed').count()
        duplicate_stockouts = session.query(VendorStockout).filter(VendorStockout.is_duplicate.is_(True)).count()
        distinct_vendor_count = session.query(VendorStockout.vendor_code).distinct().count()

        active_vendors = session.query(VendorList).filter(VendorList.is_active.is_(True)).count()
        inactive_vendors = session.query(VendorList).filter(VendorList.is_active.is_(False)).count()
        active_emails = session.query(VendorEmail).filter(VendorEmail.is_active.is_(True)).count()

        email_total = session.query(EmailSendLog).count()
        email_success = session.query(EmailSendLog).filter(EmailSendLog.status == 'sent').count()
        email_failed = session.query(EmailSendLog).filter(EmailSendLog.status == 'failed').count()
        email_pending = session.query(EmailSendLog).filter(EmailSendLog.status == 'pending').count()
        email_success_rate = round(email_success / email_total * 100, 1) if email_total else 0

        latest_import = session.query(VendorStockout).order_by(desc(VendorStockout.created_at)).first()
        latest_email = session.query(EmailSendLog).order_by(desc(EmailSendLog.created_at)).first()
        latest_batch_time = func.max(VendorStockout.created_at).label('latest_date')
        latest_batch = session.query(
            VendorStockout.batch_id,
            func.count(VendorStockout.id).label('record_count'),
            latest_batch_time
        ).group_by(VendorStockout.batch_id).order_by(desc(latest_batch_time)).first()

        return {
            'total_stockouts': total_stockouts,
            'pending_stockouts': pending_stockouts,
            'sent_stockouts': sent_stockouts,
            'failed_stockouts': failed_stockouts,
            'duplicate_stockouts': duplicate_stockouts,
            'distinct_vendor_count': distinct_vendor_count,
            'active_vendors': active_vendors,
            'inactive_vendors': inactive_vendors,
            'active_emails': active_emails,
            'email_total': email_total,
            'email_success': email_success,
            'email_failed': email_failed,
            'email_pending': email_pending,
            'email_success_rate': email_success_rate,
            'latest_import_time': latest_import.created_at if latest_import else None,
            'latest_import_vendor': latest_import.vendor_name if latest_import else None,
            'latest_import_product': latest_import.product_name if latest_import else None,
            'latest_email_time': latest_email.created_at if latest_email else None,
            'latest_email_status': latest_email.status if latest_email else None,
            'latest_email_vendor_id': latest_email.vendor_id if latest_email else None,
            'latest_batch_id': latest_batch.batch_id if latest_batch else None,
            'latest_batch_count': latest_batch.record_count if latest_batch else 0,
            'latest_batch_time': latest_batch.latest_date if latest_batch else None,
        }
    finally:
        session.close()


def _apply_stockout_filters(query, batch_id=None, vendor_keyword=None):
    if batch_id:
        query = query.filter(VendorStockout.batch_id == batch_id)

    if vendor_keyword:
        query = query.filter(or_(
            VendorStockout.vendor_code.like(f'%{vendor_keyword}%'),
            VendorStockout.vendor_name.like(f'%{vendor_keyword}%'),
            VendorStockout.product_code.like(f'%{vendor_keyword}%'),
            VendorStockout.product_name.like(f'%{vendor_keyword}%')
        ))

    return query


def _apply_stockout_status_filter(query, status_filter):
    if status_filter == 'pending':
        return query.filter(_pending_stockout_filter()), status_filter
    if status_filter in ['sent', 'failed']:
        return query.filter(VendorStockout.status == status_filter), status_filter
    if status_filter == 'duplicate':
        return query.filter(VendorStockout.is_duplicate.is_(True)), status_filter
    return query, 'all'


def _apply_stockout_sort(query, sort_by):
    if sort_by == 'created_asc':
        return query.order_by(VendorStockout.created_at.asc()), sort_by
    if sort_by == 'vendor_asc':
        return query.order_by(VendorStockout.vendor_code.asc(), VendorStockout.created_at.desc()), sort_by
    if sort_by == 'stockout_days_desc':
        return query.order_by(
            VendorStockout.stockout_days.desc().nullslast(),
            VendorStockout.created_at.desc()
        ), sort_by
    return query.order_by(VendorStockout.created_at.desc()), 'created_desc'


def get_vendor_stockout_list_context(
    vendor_db,
    page=1,
    page_size=30,
    status_filter='all',
    batch_filter='',
    vendor_keyword='',
    sort_by='created_desc',
):
    """缺貨清單 V2：以資料庫真實資料組裝篩選、分頁與列表。"""
    page = max(page or 1, 1)
    page_size = min(max(page_size or 30, 10), 100)
    status_filter = (status_filter or 'all').strip()
    batch_filter = (batch_filter or '').strip()
    vendor_keyword = (vendor_keyword or '').strip()
    sort_by = (sort_by or 'created_desc').strip()

    session = vendor_db.get_session()
    try:
        filtered_base = _apply_stockout_filters(
            session.query(VendorStockout),
            batch_filter,
            vendor_keyword
        )

        query, status_filter = _apply_stockout_status_filter(filtered_base, status_filter)
        query, sort_by = _apply_stockout_sort(query, sort_by)

        total_items = query.count()
        total_pages = max((total_items + page_size - 1) // page_size, 1)
        if page > total_pages:
            page = total_pages

        records = query.offset((page - 1) * page_size).limit(page_size).all()

        latest_batch_time = func.max(VendorStockout.created_at).label('latest_date')
        batches = session.query(
            VendorStockout.batch_id,
            func.count(VendorStockout.id).label('record_count'),
            latest_batch_time
        ).group_by(VendorStockout.batch_id).order_by(desc(latest_batch_time)).limit(30).all()

        return {
            'records': records,
            'batches': batches,
            'total_items': total_items,
            'total_pages': total_pages,
            'current_page': page,
            'page_size': page_size,
            'current_status': status_filter,
            'current_batch': batch_filter,
            'search_query': vendor_keyword,
            'current_sort': sort_by,
            'stats': {
                'total': filtered_base.count(),
                'pending': filtered_base.filter(_pending_stockout_filter()).count(),
                'sent': filtered_base.filter(VendorStockout.status == 'sent').count(),
                'failed': filtered_base.filter(VendorStockout.status == 'failed').count(),
                'duplicate': filtered_base.filter(VendorStockout.is_duplicate.is_(True)).count(),
                'vendor_count': filtered_base.with_entities(VendorStockout.vendor_code).distinct().count(),
            }
        }
    finally:
        session.close()


def _apply_stockout_api_filters(query, batch_number=None, vendor_filter=None):
    if batch_number:
        query = query.filter(VendorStockout.batch_id == batch_number)

    if vendor_filter:
        query = query.filter(or_(
            VendorStockout.vendor_code.like(f'%{vendor_filter}%'),
            VendorStockout.vendor_name.like(f'%{vendor_filter}%')
        ))

    return query


def _apply_stockout_api_sort(query, sort_by):
    if sort_by == 'created_at_asc':
        return query.order_by(VendorStockout.created_at.asc())
    if sort_by == 'vendor_code_asc':
        return query.order_by(VendorStockout.vendor_code.asc())
    if sort_by == 'stockout_days_desc':
        return query.order_by(VendorStockout.safe_stock_days.desc())
    return query.order_by(VendorStockout.created_at.desc())


def _serialize_stockout_record(record):
    return {
        'id': record.id,
        'batch_number': record.batch_id,
        'vendor_code': record.vendor_code,
        'vendor_name': record.vendor_name,
        'product_code': record.product_code,
        'product_name': record.product_name,
        'stockout_days': record.safe_stock_days,
        'daily_avg_sales': float(record.daily_avg_sales) if record.daily_avg_sales else None,
        'current_stock': record.current_stock,
        'send_status': record.status or 'pending',
        'created_at': record.created_at.isoformat() if record.created_at else None,
        'notes': record.notes
    }


def get_stockout_api_list_payload(
    vendor_db,
    page=1,
    page_size=50,
    batch_number=None,
    vendor_filter=None,
    status_filter=None,
    sort_by='created_at_desc',
):
    """回傳舊版缺貨清單 API 相容 payload。"""
    page = page or 1
    page_size = page_size or 50

    session = vendor_db.get_session()
    try:
        query = _apply_stockout_api_filters(
            session.query(VendorStockout),
            batch_number=batch_number,
            vendor_filter=vendor_filter
        )

        if status_filter:
            query = query.filter(VendorStockout.status == status_filter)

        query = _apply_stockout_api_sort(query, sort_by)
        total = query.count()
        records = query.offset((page - 1) * page_size).limit(page_size).all()

        stats_query = _apply_stockout_api_filters(
            session.query(VendorStockout),
            batch_number=batch_number,
            vendor_filter=vendor_filter
        )
        total_stats = stats_query.count()
        pending_count = stats_query.filter(_pending_stockout_filter()).count()
        sent_count = stats_query.filter(VendorStockout.status == 'sent').count()
        vendor_count = session.query(VendorStockout.vendor_code).distinct().count()

        return {
            'records': [_serialize_stockout_record(record) for record in records],
            'total': total,
            'page': page,
            'page_size': page_size,
            'stats': {
                'total': total_stats,
                'pending': pending_count,
                'sent': sent_count,
                'vendor_count': vendor_count
            }
        }
    finally:
        session.close()


def get_stockout_batches_payload(vendor_db):
    """回傳舊版批次清單 API 相容 payload。"""
    session = vendor_db.get_session()
    try:
        batches = session.query(
            VendorStockout.batch_id,
            func.count(VendorStockout.id).label('count'),
            func.max(VendorStockout.created_at).label('latest_date')
        ).group_by(VendorStockout.batch_id)\
         .order_by(desc('latest_date'))\
         .all()

        return [
            {
                'batch_number': batch.batch_id,
                'count': batch.count,
                'latest_date': batch.latest_date.isoformat() if batch.latest_date else None
            }
            for batch in batches
        ]
    finally:
        session.close()


def _serialize_vendor(vendor, emails):
    return {
        'id': vendor.id,
        'vendor_code': vendor.vendor_code,
        'vendor_name': vendor.vendor_name,
        'is_active': vendor.is_active,
        'email_count': len(emails),
        'emails': emails,
        'created_at': vendor.created_at.isoformat() if vendor.created_at else None
    }


def get_vendor_list_payload(
    vendor_db,
    page=1,
    page_size=20,
    search='',
    active_only=True,
):
    """回傳舊版廠商清單 API 相容 payload。"""
    page = page or 1
    page_size = page_size or 20
    search = (search or '').strip()

    session = vendor_db.get_session()
    try:
        query = session.query(VendorList)

        if active_only:
            query = query.filter(VendorList.is_active.is_(True))

        if search:
            query = query.filter(or_(
                VendorList.vendor_code.like(f'%{search}%'),
                VendorList.vendor_name.like(f'%{search}%')
            ))

        total = query.count()
        vendors = query.order_by(VendorList.vendor_code.asc())\
            .offset((page - 1) * page_size)\
            .limit(page_size)\
            .all()

        vendors_data = []
        for vendor in vendors:
            emails = [
                email.email
                for email in session.query(VendorEmail).filter(
                    VendorEmail.vendor_id == vendor.id,
                    VendorEmail.is_active.is_(True)
                ).all()
            ]
            vendors_data.append(_serialize_vendor(vendor, emails))

        total_vendors = session.query(VendorList).filter(VendorList.is_active.is_(True)).count()
        total_emails = session.query(VendorEmail).filter(VendorEmail.is_active.is_(True)).count()
        avg_emails = round(total_emails / total_vendors, 1) if total_vendors > 0 else 0

        return {
            'vendors': vendors_data,
            'total': total,
            'page': page,
            'page_size': page_size,
            'stats': {
                'total_vendors': total_vendors,
                'total_emails': total_emails,
                'avg_emails': avg_emails
            }
        }
    finally:
        session.close()


def get_vendor_detail_payload(vendor_db, vendor_code):
    """回傳單一廠商 API 相容 payload；找不到時回傳 None。"""
    session = vendor_db.get_session()
    try:
        vendor = session.query(VendorList).filter_by(vendor_code=vendor_code).first()
        if not vendor:
            return None

        emails = [
            email.email
            for email in session.query(VendorEmail).filter(
                VendorEmail.vendor_id == vendor.id,
                VendorEmail.is_active.is_(True)
            ).all()
        ]

        return _serialize_vendor(vendor, emails)
    finally:
        session.close()
