import os
import uuid
import json
from datetime import datetime
from flask import Flask, jsonify, request
from dotenv import load_dotenv
from supabase import create_client, Client
from werkzeug.utils import secure_filename
from openai import OpenAI

# Load environment variables
load_dotenv()

app = Flask(__name__)

# Initialize Supabase client with service role key
supabase_url = os.getenv('SUPABASE_URL')
supabase_service_role_key = os.getenv('SUPABASE_SERVICE_ROLE_KEY')

if not supabase_url or not supabase_service_role_key:
    raise Exception("Missing SUPABASE_URL or SUPABASE_SERVICE_ROLE_KEY environment variables")

supabase: Client = create_client(supabase_url, supabase_service_role_key)

@app.route('/')
def hello_flask():
    return "hello flask"

@app.route('/supabase-test')
def supabase_test():
    try:
        # Get user list using admin API
        users_response = supabase.auth.admin.list_users()
        user_count = len(users_response)
        
        return jsonify({
            "status": "success",
            "message": "Supabase connection successful",
            "user_count": user_count
        })
    except Exception as e:
        return jsonify({
            "status": "error",
            "message": f"Supabase connection failed: {str(e)}"
        }), 500

@app.route('/upload-audio', methods=['POST'])
def upload_audio():
    try:
        # Check if file is present in request
        if 'audio' not in request.files:
            return jsonify({
                "status": "error",
                "message": "No audio file provided"
            }), 400
        
        file = request.files['audio']
        
        # Check if file is selected
        if file.filename == '':
            return jsonify({
                "status": "error", 
                "message": "No file selected"
            }), 400
        
        # Check file extension
        if not file.filename.lower().endswith('.m4a'):
            return jsonify({
                "status": "error",
                "message": "Only .m4a files are allowed"
            }), 400
        
        # Generate unique filename
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        unique_id = str(uuid.uuid4())[:8]
        filename = f"audio_{timestamp}_{unique_id}.m4a"
        
        # Read file content
        file_content = file.read()
        
        # Upload to Supabase storage
        storage_response = supabase.storage.from_("user-audio").upload(
            filename, 
            file_content,
            {
                "content-type": "audio/mp4"
            }
        )
        
        if storage_response.status_code != 200:
            return jsonify({
                "status": "error",
                "message": f"Failed to upload to storage: {storage_response.text}"
            }), 500
        
        # Get public URL
        public_url = supabase.storage.from_("user-audio").get_public_url(filename)
        
        return jsonify({
            "status": "success",
            "message": "Audio file uploaded successfully",
            "filename": filename,
            "url": public_url
        })
        
    except Exception as e:
        return jsonify({
            "status": "error",
            "message": f"Upload failed: {str(e)}"
        }), 500

@app.route('/parse-audio', methods=['POST'])
def parse_audio():
    try:
        data = request.get_json()
        
        if not data or 'audio_url' not in data:
            return jsonify({
                "status": "error",
                "message": "Missing audio_url parameter"
            }), 400
        
        audio_url = data['audio_url']
        categories = data.get('categories', [])
        
        # 准备分类信息给AI参考
        category_text = "可用分类: " + ", ".join([f"{cat['name']}({cat['iconName']})" for cat in categories]) if categories else "分类: 餐饮, 交通, 购物, 娱乐, 医疗, 其他"
        
        # 初始化阿里云客户端
        client = OpenAI(
            api_key=os.getenv("DASHSCOPE_API_KEY"),
            base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
        )
        
        # 调用AI解析语音
        completion = client.chat.completions.create(
            model="qwen-omni-turbo",
            messages=[
                {
                    "role": "user",
                    "content": [
                        {
                            "type": "input_audio",
                            "input_audio": {
                                "data": audio_url,
                                "format": "m4a",
                            },
                        },
                        {
                            "type": "text", 
                            "text": f"""请解析这段语音中的记账信息，返回JSON格式。{category_text}

分类选择规则：
- 书籍、杂志、教材、小说、漫画等 → 选择"书籍"分类
- 食物、饮料、餐厅、外卖等 → 选择"餐饮"分类  
- 衣服、鞋子、包包、化妆品等日用品 → 选择"购物"分类
- 打车、地铁、公交、加油等 → 选择"交通"分类
- 电影、游戏、KTV、旅游等 → 选择"娱乐"分类
- 看病、买药、体检等 → 选择"医疗"分类
- 其他无法明确分类的 → 选择"其他"分类

标题提取规则：
- 只提取消费的核心物品或服务名称，去掉动词和修饰词
- 例如："买了一本书" → "书"
- 例如："今天吃了午餐" → "午餐"  
- 例如："打车回家" → "打车"
- 例如："看了电影" → "电影"
- 例如："买了一件衣服" → "衣服"
- 保持简洁，突出消费的核心内容

要求返回格式：
{{
  "expenses": [
    {{
      "amount": 数字,
      "title": "消费核心名称",
      "category": "分类名称"
    }}
  ]
}}

如果语音中包含多条记账信息，请全部解析出来。金额必须是数字类型，标题请按照上述规则提取核心名称，分类请严格按照分类规则选择。"""
                        },
                    ],
                },
            ],
            stream=True,
            stream_options={"include_usage": True},
        )
        
        # 收集流式响应
        ai_response = ""
        for chunk in completion:
            if chunk.choices and chunk.choices[0].delta and chunk.choices[0].delta.content:
                ai_response += chunk.choices[0].delta.content
        
        print(f"🤖 AI完整响应: {ai_response}")
        print(f"📏 响应长度: {len(ai_response)}")
        
        # 清理AI响应中的markdown代码块标记
        cleaned_response = ai_response.strip()
        if cleaned_response.startswith('```json'):
            cleaned_response = cleaned_response[7:]  # 移除 ```json
        if cleaned_response.startswith('```'):
            cleaned_response = cleaned_response[3:]   # 移除 ```
        if cleaned_response.endswith('```'):
            cleaned_response = cleaned_response[:-3]  # 移除结尾的 ```
        cleaned_response = cleaned_response.strip()
        
        print(f"🧹 清理后的响应: {cleaned_response}")
        
        try:
            # 尝试解析JSON
            parsed_data = json.loads(cleaned_response)
            print(f"✅ JSON解析成功: {parsed_data}")
            expenses = parsed_data.get('expenses', [])
            print(f"💰 提取到的expenses: {expenses}")
            
            # 验证数据格式
            validated_expenses = []
            for expense in expenses:
                print(f"🔍 验证expense: {expense}")
                if all(key in expense for key in ['amount', 'title', 'category']):
                    # 确保amount是数字
                    try:
                        amount = float(expense['amount'])
                        validated_expense = {
                            'amount': amount,
                            'title': str(expense['title']).strip(),
                            'category': str(expense['category']).strip()
                        }
                        validated_expenses.append(validated_expense)
                        print(f"✅ 验证通过: {validated_expense}")
                    except (ValueError, TypeError) as e:
                        print(f"❌ 金额转换失败: {e}")
                        continue
                else:
                    print(f"❌ 缺少必要字段: {expense}")
            
            print(f"📊 最终验证的expenses: {validated_expenses}")
            
            if not validated_expenses:
                print("⚠️ 没有找到有效的记账信息")
                return jsonify({
                    "status": "error",
                    "message": "AI解析结果中没有找到有效的记账信息",
                    "ai_response": ai_response
                }), 400
            
            return jsonify({
                "status": "success",
                "message": "语音解析成功",
                "expenses": validated_expenses,
                "raw_response": ai_response
            })
            
        except json.JSONDecodeError as e:
            print(f"❌ JSON解析失败: {e}")
            print(f"🔍 尝试解析的内容: '{cleaned_response}'")
            # 如果AI返回的不是标准JSON，尝试提取关键信息
            return jsonify({
                "status": "error",
                "message": "AI返回格式解析失败",
                "ai_response": ai_response,
                "cleaned_response": cleaned_response
            }), 500
        
    except Exception as e:
        return jsonify({
            "status": "error",
            "message": f"语音解析失败: {str(e)}"
        }), 500

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=9001) 