#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
全国高铁列车时刻表查询脚本

支持多种数据源：
1. 天行数据（免费，100 次/天）
2. 聚合数据（免费，100 次/天）
3. 本地缓存（SQLite/JSON）

使用方法：
    python query.py --from 北京 --to 西安 --date 2026-03-15
    python query.py --from 北京 --to 上海 --api tianapi --key YOUR_KEY
"""

import requests
import json
import sqlite3
import os
from datetime import datetime, timedelta
from typing import List, Dict, Optional
import sys

# 配置
CONFIG = {
    "tianapi_key": "",  # 天行数据 API Key（可能已下架）
    "juhe_key": "",     # 聚合数据 API Key ⭐ 推荐
    "cache_enabled": True,
    "cache_expire_hours": 24,
    "db_path": os.path.join(os.path.dirname(__file__), "train_schedule.db")
}


class TrainScheduleQuery:
    """火车时刻表查询类"""
    
    def __init__(self, api_key: str = "", source: str = "tianapi"):
        """
        初始化查询器
        
        Args:
            api_key: API Key
            source: 数据源（tianapi/juhe/local）
        """
        self.api_key = api_key or CONFIG.get(f"{source}_key", "")
        self.source = source
        self.session = requests.Session()
        self.session.headers.update({
            "User-Agent": "Mozilla/5.0 (compatible; TravelAgent/1.0)"
        })
        
        if CONFIG["cache_enabled"]:
            self._init_db()
    
    def _init_db(self):
        """初始化 SQLite 数据库"""
        conn = sqlite3.connect(CONFIG["db_path"])
        cursor = conn.cursor()
        
        # 创建车次表
        cursor.execute("""
            CREATE TABLE IF NOT EXISTS trains (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                train_no TEXT NOT NULL,
                from_station TEXT NOT NULL,
                to_station TEXT NOT NULL,
                departure_time TEXT,
                arrival_time TEXT,
                duration TEXT,
                distance INTEGER,
                query_date TEXT,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                UNIQUE(train_no, from_station, to_station, query_date)
            )
        """)
        
        # 创建站点表
        cursor.execute("""
            CREATE TABLE IF NOT EXISTS stations (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                station_name TEXT UNIQUE NOT NULL,
                station_code TEXT,
                city_name TEXT,
                province TEXT
            )
        """)
        
        # 创建索引
        cursor.execute("CREATE INDEX IF NOT EXISTS idx_train_route ON trains(from_station, to_station)")
        cursor.execute("CREATE INDEX IF NOT EXISTS idx_train_no ON trains(train_no)")
        
        conn.commit()
        conn.close()
    
    def query_tianapi(self, from_station: str, to_station: str, date: str = None) -> Dict:
        """
        使用天行数据查询车次
        
        API 文档：https://www.tianapi.com/apiview/163
        
        Args:
            from_station: 出发站
            to_station: 到达站
            date: 查询日期（YYYY-MM-DD）
        
        Returns:
            dict: 查询结果
        """
        if not self.api_key:
            raise ValueError("天行数据 API Key 未配置")
        
        if not date:
            date = datetime.now().strftime("%Y-%m-%d")
        
        url = "http://v.tianapi.com/train/index"
        params = {
            "key": self.api_key,
            "from": from_station,
            "to": to_station,
            "date": date
        }
        
        try:
            response = self.session.get(url, params=params, timeout=10)
            response.raise_for_status()
            result = response.json()
            
            if result.get("code") == 200:
                return result
            else:
                print(f"天行数据查询失败：{result.get('msg', '未知错误')}")
                return {"code": result.get("code", 500), "msg": result.get("msg", "查询失败")}
        
        except requests.exceptions.RequestException as e:
            print(f"网络请求失败：{e}")
            return {"code": 500, "msg": f"网络错误：{str(e)}"}
    
    def query_juhe(self, from_station: str, to_station: str, date: str = None) -> Dict:
        """
        使用聚合数据查询车次 ⭐ 推荐
        
        API 文档：https://www.juhe.cn/docs/api/id/18
        
        Args:
            from_station: 出发站
            to_station: 到达站
            date: 查询日期（YYYY-MM-DD）
        
        Returns:
            dict: 查询结果
        """
        if not self.api_key:
            raise ValueError("聚合数据 API Key 未配置")
        
        if not date:
            date = datetime.now().strftime("%Y-%m-%d")
        
        url = "http://v.juhe.cn/train/s2s"
        params = {
            "key": self.api_key,
            "from": from_station,
            "to": to_station,
            "date": date
        }
        
        try:
            response = self.session.get(url, params=params, timeout=10)
            response.raise_for_status()
            result = response.json()
            
            # 聚合数据返回格式
            if result.get("error_code") == 0:
                # 转换为统一格式
                trains = []
                result_list = result.get("result", [])
                if isinstance(result_list, dict):
                    result_list = result_list.get("list", [])
                
                for item in result_list:
                    train = {
                        "train_no": item.get("train_no", ""),
                        "from_station": item.get("from_station_name", from_station),
                        "to_station": item.get("to_station_name", to_station),
                        "departure_time": item.get("start_time", ""),
                        "arrival_time": item.get("end_time", ""),
                        "duration": item.get("lishi", "")
                    }
                    trains.append(train)
                
                return {"code": 200, "msg": "success", "result": trains}
            else:
                print(f"聚合数据查询失败：{result.get('reason', '未知错误')}")
                return {"code": result.get("error_code", 500), "msg": result.get("reason", "查询失败")}
        
        except requests.exceptions.RequestException as e:
            print(f"网络请求失败：{e}")
            return {"code": 500, "msg": f"网络错误：{str(e)}"}
    
    def query_local(self, from_station: str, to_station: str, date: str = None) -> List[Dict]:
        """
        从本地缓存查询车次
        
        Args:
            from_station: 出发站
            to_station: 到达站
            date: 查询日期
        
        Returns:
            list: 车次列表
        """
        if not CONFIG["cache_enabled"]:
            return []
        
        conn = sqlite3.connect(CONFIG["db_path"])
        cursor = conn.cursor()
        
        # 查询缓存（24 小时内）
        expire_date = (datetime.now() - timedelta(hours=CONFIG["cache_expire_hours"])).strftime("%Y-%m-%d")
        
        cursor.execute("""
            SELECT train_no, from_station, to_station, departure_time, arrival_time, duration
            FROM trains
            WHERE from_station = ? AND to_station = ? AND query_date >= ?
            ORDER BY departure_time
        """, (from_station, to_station, expire_date))
        
        rows = cursor.fetchall()
        conn.close()
        
        trains = []
        for row in rows:
            trains.append({
                "train_no": row[0],
                "from_station": row[1],
                "to_station": row[2],
                "departure_time": row[3],
                "arrival_time": row[4],
                "duration": row[5]
            })
        
        return trains
    
    def cache_train(self, train_data: Dict, query_date: str):
        """
        缓存车次数据到本地
        
        Args:
            train_data: 车次数据
            query_date: 查询日期
        """
        if not CONFIG["cache_enabled"]:
            return
        
        conn = sqlite3.connect(CONFIG["db_path"])
        cursor = conn.cursor()
        
        try:
            cursor.execute("""
                INSERT OR REPLACE INTO trains 
                (train_no, from_station, to_station, departure_time, arrival_time, duration, query_date)
                VALUES (?, ?, ?, ?, ?, ?, ?)
            """, (
                train_data.get("train_no"),
                train_data.get("from_station"),
                train_data.get("to_station"),
                train_data.get("departure_time"),
                train_data.get("arrival_time"),
                train_data.get("duration"),
                query_date
            ))
            conn.commit()
        except Exception as e:
            print(f"缓存失败：{e}")
        finally:
            conn.close()
    
    def query(self, from_station: str, to_station: str, date: str = None, use_cache: bool = True) -> Dict:
        """
        统一查询接口（优先查缓存，缓存没有则调用 API）
        
        Args:
            from_station: 出发站
            to_station: 到达站
            date: 查询日期
            use_cache: 是否使用缓存
        
        Returns:
            dict: 查询结果
        """
        # 优先查缓存
        if use_cache:
            cached = self.query_local(from_station, to_station, date)
            if cached:
                print(f"✓ 从缓存获取到 {len(cached)} 条车次信息")
                return {"code": 200, "msg": "success", "result": cached}
        
        # 缓存没有，调用 API
        print(f"→ 正在查询 {from_station} → {to_station} 的车次...")
        
        # ⭐ 推荐使用聚合数据
        if self.source == "juhe":
            result = self.query_juhe(from_station, to_station, date)
        elif self.source == "tianapi":
            result = self.query_tianapi(from_station, to_station, date)
        else:
            return {"code": 400, "msg": f"不支持的数据源：{self.source}"}
        
        # 缓存结果
        if result.get("code") == 200 and result.get("result"):
            trains = result.get("result", [])
            for train in trains:
                self.cache_train(train, date or datetime.now().strftime("%Y-%m-%d"))
            print(f"✓ 查询成功，获取到 {len(trains)} 条车次信息")
        
        return result


def main():
    """主函数"""
    import argparse
    
    parser = argparse.ArgumentParser(description="全国高铁列车时刻表查询")
    parser.add_argument("--from", dest="from_station", required=True, help="出发站")
    parser.add_argument("--to", dest="to_station", required=True, help="到达站")
    parser.add_argument("--date", default=None, help="查询日期（YYYY-MM-DD，默认今天）")
    parser.add_argument("--api", default="tianapi", choices=["tianapi", "juhe"], help="API 服务商")
    parser.add_argument("--key", default="", help="API Key")
    parser.add_argument("--no-cache", action="store_true", help="不使用缓存")
    
    args = parser.parse_args()
    
    # 创建查询器
    query = TrainScheduleQuery(api_key=args.key, source=args.api)
    
    # 查询
    result = query.query(
        from_station=args.from_station,
        to_station=args.to_station,
        date=args.date,
        use_cache=not args.no_cache
    )
    
    # 输出结果
    if result.get("code") == 200:
        trains = result.get("result", [])
        print(f"\n{'车次':<10} {'出发站':<10} {'到达站':<10} {'出发时间':<10} {'到达时间':<10} {'历时':<10}")
        print("-" * 70)
        for train in trains[:20]:  # 只显示前 20 条
            print(f"{train.get('train_no', 'N/A'):<10} "
                  f"{train.get('from_station', 'N/A'):<10} "
                  f"{train.get('to_station', 'N/A'):<10} "
                  f"{train.get('departure_time', 'N/A'):<10} "
                  f"{train.get('arrival_time', 'N/A'):<10} "
                  f"{train.get('duration', 'N/A'):<10}")
        
        if len(trains) > 20:
            print(f"... 还有 {len(trains) - 20} 条车次，请使用 API 查看完整结果")
    else:
        print(f"查询失败：{result.get('msg', '未知错误')}")


if __name__ == "__main__":
    main()
