# 既存のインポート部分に追加
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework import status
from rog.models import NewEvent2, Entry, Waypoint, GpsLog
import logging
from django.db.models import F, Q, Max, Count
from datetime import datetime, timedelta
from django.utils import timezone

logger = logging.getLogger(__name__)

"""
解説
この実装では2つのエンドポイントを提供しています：

1. /realtimeMonitor (全チーム対象)

すべてのチームの最新位置情報を取得するエンドポイントです。

- パラメータ：
    - event_code：イベントコード（必須）
    - class：クラス名（省略可）

主な機能：

    - スタート済みの全チームの最新位置情報を返す
    - クラス名でフィルタリングできる
    - 各チームの状態（未スタート、競技中、ゴール済）、経過時間、スコア、チェックポイント数などの情報を提供
    - 位置情報の「鮮度」を評価（5分以内は「新鮮」、5分～30分は「通常」、30分以上は「古い」）
    - GeoJSON形式のデータも提供し、地図表示に使いやすくしている

2. /realtimeMonitor_zekken_narrow (特定チーム対象)

特定のゼッケン番号を持つチームの詳細な位置情報を取得するエンドポイントです。

- パラメータ：
    - event_code：イベントコード（必須）
    - zekken：ゼッケン番号（必須）
    - class：クラス名（省略可）

- 主な機能：
    - 指定されたゼッケン番号を持つチームの詳細データを返す
    - 最新の位置情報だけでなく、複数の過去の位置情報も提供（最新10件）
    - クラス名が指定された場合、そのクラスに所属しているか確認する
    - チームの状態、経過時間、スコア、チェックポイント数などの詳細情報を提供
    - GeoJSON形式で以下のデータを提供：
        - 最新位置（特別なマーカー）
        - 過去の位置（別のマーカー）
        - 移動経路（ライン）

この2つのエンドポイントにより、ウェブ上でリアルタイムのモニタリングダッシュボードを実現できます。
全チームの概要を一覧表示し、特定チームを選択すると詳細な移動履歴を確認できる仕組みです。
"""

@api_view(['GET'])
def realtime_monitor(request):
    """
    リアルタイムのチーム位置情報を取得
    
    パラメータ:
    - event_code: イベントコード
    - class: クラス名（省略可）
    """
    logger.info("realtime_monitor called")
    
    # リクエストからパラメータを取得
    event_code = request.query_params.get('event_code')
    class_name = request.query_params.get('class')
    
    # パラメータの別名対応
    if not event_code:
        event_code = request.query_params.get('event')
    
    logger.debug(f"Parameters: event_code={event_code}, class={class_name}")
    
    # パラメータ検証
    if not event_code:
        logger.warning("Missing required event_code parameter")
        return Response({
            "status": "ERROR", 
            "message": "イベントコードが必要です"
        }, status=status.HTTP_400_BAD_REQUEST)
    
    try:
        # イベントの存在確認
        event = NewEvent2.objects.filter(event_name=event_code).first()
        if not event:
            logger.warning(f"Event not found: {event_code}")
            return Response({
                "status": "ERROR", 
                "message": "指定されたイベントが見つかりません"
            }, status=status.HTTP_404_NOT_FOUND)
        
        # スタート済みのチームをクエリ
        entries_query = Entry.objects.filter(
            event=event,
            start_info__isnull=False
        )
        
        # クラス名でフィルタリング（指定があれば）
        if class_name:
            entries_query = entries_query.filter(class_name=class_name)
        
        # 各チームの最新ウェイポイントを取得するためのサブクエリ
        subquery = Waypoint.objects.filter(
            entry=OuterRef('pk')
        ).order_by('-recorded_at').values('latitude', 'longitude', 'recorded_at', 'speed', 'altitude')[:1]
        
        # 各チームのチェックポイント数を取得するためのサブクエリ
        cp_count_subquery = GpsLog.objects.filter(
            entry=OuterRef('pk')
        ).values('entry').annotate(count=Count('id')).values('count')
        
        # アノテーションを追加してサブクエリの結果をメインクエリに結合
        entries_with_latest_waypoint = entries_query.annotate(
            latest_latitude=Subquery(subquery.values('latitude')[:1]),
            latest_longitude=Subquery(subquery.values('longitude')[:1]),
            latest_recorded_at=Subquery(subquery.values('recorded_at')[:1]),
            latest_speed=Subquery(subquery.values('speed')[:1]),
            latest_altitude=Subquery(subquery.values('altitude')[:1]),
            checkpoint_count=Coalesce(Subquery(cp_count_subquery), 0)
        ).filter(
            # 最新ウェイポイントがあるチームのみ
            latest_latitude__isnull=False
        )
        
        # 現在時刻を取得
        now = timezone.now()
        
        # 各チームのリアルタイム情報を収集
        teams_data = []
        
        for entry in entries_with_latest_waypoint:
            # ウェイポイントがないチームはスキップ
            if not hasattr(entry, 'latest_latitude') or not entry.latest_latitude:
                continue
            
            # 最新の位置情報の取得時刻
            location_time = entry.latest_recorded_at
            location_age_seconds = (now - location_time).total_seconds() if location_time else None
            
            # 位置情報の鮮度を評価（5分以内は新鮮、30分以上は古い）
            location_freshness = "fresh" if location_age_seconds and location_age_seconds < 300 else \
                                "normal" if location_age_seconds and location_age_seconds < 1800 else "stale"
            
            # スタート、ゴール情報を取得
            start_time = entry.start_info.start_time if hasattr(entry, 'start_info') else None
            goal_time = entry.goal_info.goal_time if hasattr(entry, 'goal_info') else None
            score = entry.goal_info.score if hasattr(entry, 'goal_info') and hasattr(entry.goal_info, 'score') else None
            
            # 経過時間を計算
            elapsed_time = None
            if start_time:
                end_time = goal_time if goal_time else now
                elapsed_seconds = (end_time - start_time).total_seconds()
                
                # 時間:分:秒の形式にフォーマット
                hours, remainder = divmod(int(elapsed_seconds), 3600)
                minutes, seconds = divmod(remainder, 60)
                elapsed_time = f"{hours:02}:{minutes:02}:{seconds:02}"
            
            # チームステータスを判定
            if goal_time:
                status_text = "ゴール済"
            elif start_time:
                status_text = "競技中"
            else:
                status_text = "未スタート"
            
            team_data = {
                "team_name": entry.team_name,
                "zekken_number": entry.zekken_number,
                "class_name": entry.class_name,
                "status": status_text,
                "start_time": start_time.strftime("%Y-%m-%d %H:%M:%S") if start_time else None,
                "goal_time": goal_time.strftime("%Y-%m-%d %H:%M:%S") if goal_time else None,
                "elapsed_time": elapsed_time,
                "score": score,
                "checkpoint_count": entry.checkpoint_count,
                "location": {
                    "latitude": entry.latest_latitude,
                    "longitude": entry.latest_longitude,
                    "timestamp": location_time.strftime("%Y-%m-%d %H:%M:%S") if location_time else None,
                    "age_seconds": int(location_age_seconds) if location_age_seconds else None,
                    "freshness": location_freshness,
                    "speed": entry.latest_speed,
                    "altitude": entry.latest_altitude
                }
            }
            
            teams_data.append(team_data)
        
        # GeoJSON形式のデータを作成
        geo_json_features = []
        
        # 各チームのポイントフィーチャーを追加
        for team in teams_data:
            # 位置情報がないチームはスキップ
            if not team['location']['latitude'] or not team['location']['longitude']:
                continue
            
            # 位置情報の鮮度に基づいて色を変更
            color = {
                "fresh": "#00FF00",  # 緑
                "normal": "#FFFF00",  # 黄
                "stale": "#FF0000"    # 赤
            }.get(team['location']['freshness'], "#AAAAAA")  # デフォルトはグレー
            
            # ゴール済みのチームは異なるマーカーを使用
            is_goal = team['status'] == "ゴール済"
            
            geo_json_features.append({
                "type": "Feature",
                "geometry": {
                    "type": "Point",
                    "coordinates": [team['location']['longitude'], team['location']['latitude']]
                },
                "properties": {
                    "team_name": team['team_name'],
                    "zekken_number": team['zekken_number'],
                    "class_name": team['class_name'],
                    "status": team['status'],
                    "elapsed_time": team['elapsed_time'],
                    "score": team['score'],
                    "checkpoint_count": team['checkpoint_count'],
                    "timestamp": team['location']['timestamp'],
                    "age_seconds": team['location']['age_seconds'],
                    "color": color,
                    "icon": "flag-checkered" if is_goal else "map-marker-alt",
                    "iconColor": color
                }
            })
        
        geo_json = {
            "type": "FeatureCollection",
            "features": geo_json_features
        }
        
        return Response({
            "status": "OK",
            "event_code": event_code,
            "class_name": class_name,
            "timestamp": now.strftime("%Y-%m-%d %H:%M:%S"),
            "total_teams": len(teams_data),
            "teams": teams_data,
            "geo_json": geo_json
        })
    
    except Exception as e:
        logger.error(f"Error in realtime_monitor: {str(e)}")
        return Response({
            "status": "ERROR", 
            "message": "サーバーエラーが発生しました"
        }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

@api_view(['GET'])
def realtime_monitor_zekken_narrow(request):
    """
    指定ゼッケン番号のチームの位置情報を取得
    
    パラメータ:
    - event_code: イベントコード
    - class: クラス名（省略可）
    - zekken: ゼッケン番号
    """
    logger.info("realtime_monitor_zekken_narrow called")
    
    # リクエストからパラメータを取得
    event_code = request.query_params.get('event_code')
    class_name = request.query_params.get('class')
    zekken_number = request.query_params.get('zekken')
    
    # パラメータの別名対応
    if not event_code:
        event_code = request.query_params.get('event')
    
    logger.debug(f"Parameters: event_code={event_code}, class={class_name}, zekken={zekken_number}")
    
    # パラメータ検証
    if not event_code:
        logger.warning("Missing required event_code parameter")
        return Response({
            "status": "ERROR", 
            "message": "イベントコードが必要です"
        }, status=status.HTTP_400_BAD_REQUEST)
    
    if not zekken_number:
        logger.warning("Missing required zekken parameter")
        return Response({
            "status": "ERROR", 
            "message": "ゼッケン番号が必要です"
        }, status=status.HTTP_400_BAD_REQUEST)
    
    try:
        # イベントの存在確認
        event = NewEvent2.objects.filter(event_name=event_code).first()
        if not event:
            logger.warning(f"Event not found: {event_code}")
            return Response({
                "status": "ERROR", 
                "message": "指定されたイベントが見つかりません"
            }, status=status.HTTP_404_NOT_FOUND)
        
        # 指定ゼッケン番号のチームを検索
        entry = Entry.objects.filter(
            event=event,
            zekken_number=zekken_number
        ).first()
        
        if not entry:
            logger.warning(f"Team with zekken number {zekken_number} not found in event: {event_code}")
            return Response({
                "status": "ERROR", 
                "message": "指定されたゼッケン番号のチームが見つかりません"
            }, status=status.HTTP_404_NOT_FOUND)
        
        # クラス名でフィルタリング（指定があれば）
        if class_name and entry.class_name != class_name:
            logger.warning(f"Team {zekken_number} is not in class: {class_name}")
            return Response({
                "status": "ERROR", 
                "message": "指定されたクラスに所属していません"
            }, status=status.HTTP_404_NOT_FOUND)
        
        # ウェイポイントデータを取得（最新の複数件）
        waypoints = Waypoint.objects.filter(
            entry=entry
        ).order_by('-recorded_at')[:10]  # 最新10件
        
        # チェックポイント数を取得
        checkpoint_count = GpsLog.objects.filter(entry=entry).count()
        
        # 現在時刻を取得
        now = timezone.now()
        
        # スタート、ゴール情報を取得
        start_time = entry.start_info.start_time if hasattr(entry, 'start_info') else None
        goal_time = entry.goal_info.goal_time if hasattr(entry, 'goal_info') and entry.goal_info else None
        score = entry.goal_info.score if hasattr(entry, 'goal_info') and entry.goal_info and hasattr(entry.goal_info, 'score') else None
        
        # 経過時間を計算
        elapsed_time = None
        if start_time:
            end_time = goal_time if goal_time else now
            elapsed_seconds = (end_time - start_time).total_seconds()
            
            # 時間:分:秒の形式にフォーマット
            hours, remainder = divmod(int(elapsed_seconds), 3600)
            minutes, seconds = divmod(remainder, 60)
            elapsed_time = f"{hours:02}:{minutes:02}:{seconds:02}"
        
        # チームステータスを判定
        if goal_time:
            status_text = "ゴール済"
        elif start_time:
            status_text = "競技中"
        else:
            status_text = "未スタート"
        
        # ウェイポイントデータを処理
        location_data = []
        latest_location = None
        
        for i, wp in enumerate(waypoints):
            location = {
                "latitude": wp.latitude,
                "longitude": wp.longitude,
                "timestamp": wp.recorded_at.strftime("%Y-%m-%d %H:%M:%S"),
                "age_seconds": int((now - wp.recorded_at).total_seconds()),
                "speed": wp.speed,
                "altitude": wp.altitude,
                "accuracy": wp.accuracy
            }
            
            # 位置情報の鮮度を評価
            location["freshness"] = "fresh" if location["age_seconds"] < 300 else \
                                   "normal" if location["age_seconds"] < 1800 else "stale"
            
            location_data.append(location)
            
            # 最新位置情報を保存
            if i == 0:
                latest_location = location
        
        # GeoJSON形式のデータを作成
        geo_json_features = []
        
        # 最新位置のポイントフィーチャー
        if latest_location:
            color = {
                "fresh": "#00FF00",  # 緑
                "normal": "#FFFF00",  # 黄
                "stale": "#FF0000"    # 赤
            }.get(latest_location['freshness'], "#AAAAAA")  # デフォルトはグレー
            
            is_goal = status_text == "ゴール済"
            
            geo_json_features.append({
                "type": "Feature",
                "geometry": {
                    "type": "Point",
                    "coordinates": [latest_location['longitude'], latest_location['latitude']]
                },
                "properties": {
                    "team_name": entry.team_name,
                    "zekken_number": zekken_number,
                    "class_name": entry.class_name,
                    "status": status_text,
                    "timestamp": latest_location['timestamp'],
                    "color": color,
                    "icon": "flag-checkered" if is_goal else "map-marker-alt",
                    "iconColor": color,
                    "isLatest": True
                }
            })
        
        # 過去位置のポイントフィーチャー
        for i, location in enumerate(location_data):
            if i == 0:  # 最新位置は既に追加済み
                continue
                
            geo_json_features.append({
                "type": "Feature",
                "geometry": {
                    "type": "Point",
                    "coordinates": [location['longitude'], location['latitude']]
                },
                "properties": {
                    "team_name": entry.team_name,
                    "zekken_number": zekken_number,
                    "timestamp": location['timestamp'],
                    "color": "#AAAAAA",  # 過去の位置はグレー
                    "icon": "circle",
                    "iconColor": "#AAAAAA",
                    "isLatest": False
                }
            })
        
        # 移動経路を表すラインフィーチャー
        if len(location_data) >= 2:
            geo_json_features.append({
                "type": "Feature",
                "geometry": {
                    "type": "LineString",
                    "coordinates": [
                        [location['longitude'], location['latitude']] 
                        for location in reversed(location_data)  # 時系列順
                    ]
                },
                "properties": {
                    "team_name": entry.team_name,
                    "zekken_number": zekken_number,
                    "color": "#0000FF"  # 青色の線
                }
            })
        
        geo_json = {
            "type": "FeatureCollection",
            "features": geo_json_features
        }
        
        team_data = {
            "team_name": entry.team_name,
            "zekken_number": zekken_number,
            "class_name": entry.class_name,
            "status": status_text,
            "start_time": start_time.strftime("%Y-%m-%d %H:%M:%S") if start_time else None,
            "goal_time": goal_time.strftime("%Y-%m-%d %H:%M:%S") if goal_time else None,
            "elapsed_time": elapsed_time,
            "score": score,
            "checkpoint_count": checkpoint_count,
            "latest_location": latest_location,
            "locations": location_data,
            "locations_count": len(location_data)
        }
        
        return Response({
            "status": "OK",
            "event_code": event_code,
            "timestamp": now.strftime("%Y-%m-%d %H:%M:%S"),
            "team": team_data,
            "geo_json": geo_json
        })
    
    except Exception as e:
        logger.error(f"Error in realtime_monitor_zekken_narrow: {str(e)}")
        return Response({
            "status": "ERROR", 
            "message": "サーバーエラーが発生しました"
        }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
