#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
API使用統計資料模型

Author: PANJIT IT Team
Created: 2024-01-28
Modified: 2024-01-28
"""

from datetime import datetime, timedelta
from sqlalchemy.sql import func
from app import db
from app.utils.timezone import format_taiwan_time


class APIUsageStats(db.Model):
    """API使用統計表 (dt_api_usage_stats)"""
    __tablename__ = 'dt_api_usage_stats'
    
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    user_id = db.Column(db.Integer, db.ForeignKey('dt_users.id'), nullable=False, comment='使用者ID')
    job_id = db.Column(db.Integer, db.ForeignKey('dt_translation_jobs.id'), comment='任務ID')
    api_endpoint = db.Column(db.String(200), nullable=False, comment='API端點')
    prompt_tokens = db.Column(db.Integer, default=0, comment='Prompt token數')
    completion_tokens = db.Column(db.Integer, default=0, comment='Completion token數')
    total_tokens = db.Column(db.Integer, default=0, comment='總token數')
    prompt_unit_price = db.Column(db.Numeric(10, 8), default=0.00000000, comment='單價')
    prompt_price_unit = db.Column(db.String(20), default='USD', comment='價格單位')
    cost = db.Column(db.Numeric(10, 4), default=0.0000, comment='成本')
    response_time_ms = db.Column(db.Integer, default=0, comment='回應時間(毫秒)')
    success = db.Column(db.Boolean, default=True, comment='是否成功')
    error_message = db.Column(db.Text, comment='錯誤訊息')
    created_at = db.Column(db.DateTime, default=func.now(), comment='建立時間')
    
    def __repr__(self):
        return f'<APIUsageStats {self.api_endpoint}>'
    
    def to_dict(self):
        """轉換為字典格式"""
        return {
            'id': self.id,
            'user_id': self.user_id,
            'job_id': self.job_id,
            'api_endpoint': self.api_endpoint,
            'prompt_tokens': self.prompt_tokens,
            'completion_tokens': self.completion_tokens,
            'total_tokens': self.total_tokens,
            'prompt_unit_price': float(self.prompt_unit_price) if self.prompt_unit_price else 0.0,
            'prompt_price_unit': self.prompt_price_unit,
            'cost': float(self.cost) if self.cost else 0.0,
            'response_time_ms': self.response_time_ms,
            'success': self.success,
            'error_message': self.error_message,
            'created_at': format_taiwan_time(self.created_at, "%Y-%m-%d %H:%M:%S") if self.created_at else None
        }
    
    @classmethod
    def record_api_call(cls, user_id, job_id, api_endpoint, metadata, response_time_ms, success=True, error_message=None):
        """記錄 API 呼叫統計"""
        # 從 Dify API metadata 解析使用量資訊
        usage_data = metadata.get('usage', {})
        
        prompt_tokens = usage_data.get('prompt_tokens', 0)
        completion_tokens = usage_data.get('completion_tokens', 0)
        total_tokens = usage_data.get('total_tokens', prompt_tokens + completion_tokens)
        
        # 計算成本 - 使用 Dify API 提供的總成本
        if 'total_price' in usage_data:
            # 直接使用 API 提供的總價格
            cost = float(usage_data.get('total_price', 0.0))
        else:
            # 備用計算方式
            prompt_price = float(usage_data.get('prompt_price', 0.0))
            completion_price = float(usage_data.get('completion_price', 0.0))
            cost = prompt_price + completion_price
        
        # 單價資訊
        prompt_unit_price = usage_data.get('prompt_unit_price', 0.0)
        completion_unit_price = usage_data.get('completion_unit_price', 0.0)
        prompt_price_unit = usage_data.get('currency', 'USD')
        
        stats = cls(
            user_id=user_id,
            job_id=job_id,
            api_endpoint=api_endpoint,
            prompt_tokens=prompt_tokens,
            completion_tokens=completion_tokens,
            total_tokens=total_tokens,
            prompt_unit_price=prompt_unit_price,
            prompt_price_unit=prompt_price_unit,
            cost=cost,
            response_time_ms=response_time_ms,
            success=success,
            error_message=error_message
        )
        
        db.session.add(stats)
        db.session.commit()
        return stats
    
    @classmethod
    def get_user_statistics(cls, user_id, start_date=None, end_date=None):
        """取得使用者統計資料"""
        query = cls.query.filter_by(user_id=user_id)
        
        if start_date:
            query = query.filter(cls.created_at >= start_date)
        if end_date:
            query = query.filter(cls.created_at <= end_date)
        
        # 統計資料
        total_calls = query.count()
        successful_calls = query.filter_by(success=True).count()
        total_tokens = query.with_entities(func.sum(cls.total_tokens)).scalar() or 0
        total_cost = query.with_entities(func.sum(cls.cost)).scalar() or 0.0
        avg_response_time = query.with_entities(func.avg(cls.response_time_ms)).scalar() or 0
        
        return {
            'total_calls': total_calls,
            'successful_calls': successful_calls,
            'failed_calls': total_calls - successful_calls,
            'success_rate': (successful_calls / total_calls * 100) if total_calls > 0 else 0,
            'total_tokens': total_tokens,
            'total_cost': float(total_cost),
            'avg_response_time': float(avg_response_time) if avg_response_time else 0
        }
    
    @classmethod
    def get_daily_statistics(cls, days=30):
        """取得每日統計資料"""
        end_date = datetime.utcnow()
        start_date = end_date - timedelta(days=days)
        
        # 按日期分組統計
        daily_stats = db.session.query(
            func.date(cls.created_at).label('date'),
            func.count(cls.id).label('total_calls'),
            func.sum(cls.total_tokens).label('total_tokens'),
            func.sum(cls.cost).label('total_cost'),
            func.count().filter(cls.success == True).label('successful_calls')
        ).filter(
            cls.created_at >= start_date,
            cls.created_at <= end_date
        ).group_by(func.date(cls.created_at)).all()
        
        return [
            {
                'date': stat.date.isoformat(),
                'total_calls': stat.total_calls,
                'successful_calls': stat.successful_calls,
                'failed_calls': stat.total_calls - stat.successful_calls,
                'total_tokens': stat.total_tokens or 0,
                'total_cost': float(stat.total_cost or 0)
            }
            for stat in daily_stats
        ]
    
    @classmethod
    def get_top_users(cls, limit=10, start_date=None, end_date=None):
        """取得使用量排行榜"""
        query = db.session.query(
            cls.user_id,
            func.count(cls.id).label('total_calls'),
            func.sum(cls.total_tokens).label('total_tokens'),
            func.sum(cls.cost).label('total_cost')
        )
        
        if start_date:
            query = query.filter(cls.created_at >= start_date)
        if end_date:
            query = query.filter(cls.created_at <= end_date)
        
        top_users = query.group_by(cls.user_id).order_by(
            func.sum(cls.cost).desc()
        ).limit(limit).all()
        
        return [
            {
                'user_id': user.user_id,
                'total_calls': user.total_calls,
                'total_tokens': user.total_tokens or 0,
                'total_cost': float(user.total_cost or 0)
            }
            for user in top_users
        ]
    
    @classmethod
    def get_cost_trend(cls, days=30):
        """取得成本趨勢"""
        end_date = datetime.utcnow()
        start_date = end_date - timedelta(days=days)
        
        # 按日期統計成本
        cost_trend = db.session.query(
            func.date(cls.created_at).label('date'),
            func.sum(cls.cost).label('daily_cost')
        ).filter(
            cls.created_at >= start_date,
            cls.created_at <= end_date
        ).group_by(func.date(cls.created_at)).order_by(
            func.date(cls.created_at)
        ).all()
        
        return [
            {
                'date': trend.date.isoformat(),
                'cost': float(trend.daily_cost or 0)
            }
            for trend in cost_trend
        ]
    
    @classmethod
    def get_endpoint_statistics(cls):
        """取得 API 端點統計"""
        endpoint_stats = db.session.query(
            cls.api_endpoint,
            func.count(cls.id).label('total_calls'),
            func.sum(cls.cost).label('total_cost'),
            func.avg(cls.response_time_ms).label('avg_response_time')
        ).group_by(cls.api_endpoint).order_by(
            func.count(cls.id).desc()
        ).all()
        
        return [
            {
                'endpoint': stat.api_endpoint,
                'total_calls': stat.total_calls,
                'total_cost': float(stat.total_cost or 0),
                'avg_response_time': float(stat.avg_response_time or 0)
            }
            for stat in endpoint_stats
        ]