import json
import traceback
from fastapi import APIRouter, Depends, Request
from sqlalchemy.ext.asyncio import AsyncSession
from pydantic import BaseModel, ValidationError
from app.db.session import get_db
from app.models.subscription_receipt import SubscriptionReceipt
from app.core.security import validate_token
from app.api.v1.category_api import decrypt_data
from app.utils.responses import custom_response
from app.core.logging import logger
import httpx
from sqlalchemy import select, or_
import datetime
from datetime import datetime, timezone
import time
from app.core.sso import verify_subscription
from app.core.config import settings
from typing import List, Dict, Any
from app.services.android_receipt_validator import AndroidReceiptValidator
from typing import Optional, List


# from models import SubscriptionReceipts, WebhookSubscriptions, LoginHistory, PhoneNumber
# from utils import get_date_from_millisecond, log_info

router = APIRouter()

# Subscription product groups (replace with your actual product IDs)
# IOS_PRIMARY_PHONE_NUMBER_SUBSCRIPTIONS = ["prod_basic_1", "prod_basic_2"]
# IOS_SECONDARY_PHONE_NUMBER_SUBSCRIPTIONS = ["prod_additional_2"]
# IOS_TERTIARY_PHONE_NUMBER_SUBSCRIPTIONS = ["prod_additional_3"]
# IOS_GOLD_SUBSCRIPTIONS = ["prod_gold"]
# IOS_ONLY_PRO_PLUS_SUBSCRIPTIONS = ["prod_pro_plus"]

ios_plans = settings.IOS_PLANS
android_plans = settings.ANDROID_PLANS
appstore_receipt_validator_url_prod= settings.appstore_receipt_validator_url_prod
appstore_receipt_validator_url_sandbox= settings.appstore_receipt_validator_url_sandbox
sandbox_secret=settings.sandbox_secret
itunes_secret=settings.itunes_secret

def add_data_in_receipt_failed(user_id: int, error_code: str):
    """
    Replace this with your DB insert or logging logic
    to track failed receipts.
    """
    logger.error(f"Receipt validation failed for user {user_id}, error: {error_code}")


async def validate_receipt(receipt, secret, env="sandbox", exclude_old_transactions=True):
    payload = {
        "password": itunes_secret,
        "exclude-old-transactions": exclude_old_transactions,
        "receipt-data": receipt
    }

    url = appstore_receipt_validator_url_prod
    if env != 'prod':
        url = appstore_receipt_validator_url_sandbox
        if env == 'sandbox':
            payload['password'] = sandbox_secret
        else:
            payload['password'] = itunes_secret    

    async with httpx.AsyncClient(timeout=10.0) as client:
        response = await client.post(url, json=payload)
        # print("Response from Apple:", response.text)
        decoded_response = response.json()
        status = decoded_response.get("status")
        if status == 0:
            return {"isValid": True, "response": decoded_response.get("latest_receipt_info", [])}
        else:
            return {"isValid": False, "response": status}


# For android
async def get_latest_receipt_android(
    receipt: str,
    productId: str,
    userId: int = 0,
) -> List[Dict[str, Any]]:
    user_subscriptions: List[Dict[str, Any]] = []

    validator = AndroidReceiptValidator()

    logger.warning("-------- SUBSCRIPTION AndroidReceiptValidator RECEIPT------------- ")

    receiptData = validator.validateProduct(productId, receipt)

    print('receiptData',receiptData)

    if receiptData.get("isValid"):
        # validate successfully
        response = receiptData["response"]

        purchaseDateMS = response.get("startTimeMillis")
        expireDateMS = response.get("expiryTimeMillis")
        autoRenewStatus = response.get("autoRenewing")
        isInTrialPeriod = "true" if response.get("paymentState") == 2 else "false"
        cancellationDateMS = response.get("userCancellationTimeMillis", 0)

        # Google sometimes appends ".." in orderId
        order_id = response.get("orderId", "").split("..")[0]

        result = {
            "product_id": productId,
            "purchase_date_ms": purchaseDateMS,
            "original_purchase_date_ms": purchaseDateMS,
            "expires_date_ms": expireDateMS,
            "transaction_id": response.get("orderId"),
            "original_transaction_id": order_id,
            "auto_renew_status": autoRenewStatus,
            "is_trial_period": isInTrialPeriod,
            "cancellation_date_ms": cancellationDateMS,
            "receipt": receipt,  # <-- use original token, not Google's response
            "is_android": True,
        }

        user_subscriptions.append(result)

    else:
        errorResponse = receiptData.get("response")

        # Google API errors should already be dicts (from HttpError fix earlier)
        if isinstance(errorResponse, dict):
            errorCode = errorResponse.get("error", {}).get("code", "Unknown Error")
            errorMsg = errorResponse.get("error", {}).get("message", str(errorResponse))
        else:
            try:
                jsonResponse = json.loads(errorResponse)
                errorCode = jsonResponse.get("error", {}).get("code", "Unknown Error")
                errorMsg = jsonResponse.get("error", {}).get("message", str(errorResponse))
            except Exception:
                errorCode = "Unknown Error"
                errorMsg = str(errorResponse)

        logger.error(
            f"Receipt validation failed for user={userId}, "
            f"productId={productId}, code={errorCode}, message={errorMsg}"
        )
        add_data_in_receipt_failed(userId, errorCode)

    return user_subscriptions


async def get_latest_receipt(receipt, secret, user=None):
    response = await validate_receipt(receipt, secret, env="prod")
    if response["isValid"]:
        return response["response"]
    elif response["response"] in [21002, 21004, 21007]:
        logger.warning(f"Receipt validation failed with code {response['response']}, trying sandbox.")
        response = await validate_receipt(receipt, secret, env="sandbox")
        if response["isValid"]:
            return response["response"]
        else:
            logger.warning(f"Receipt validation failed for sandbox, trying testflight.")
            response = await validate_receipt(receipt, secret, env="testflight")
            if response["isValid"]:
                return response["response"]
            else:
                logger.error(f"Receipt validation failed with response: {response['response']}")
                return False
    elif response["response"] in [501, 21010]:
        logger.error(f"Receipt validation failed with response: {response['response']}")
        return False
    else:
        logger.error(f"Receipt validation failed with response: {response['response']}")
        return False
    

class SaveSubscriptionRequest(BaseModel):
    receipt: str
    productId : Optional[str] =None

@router.post("/subscription/save")
async def save_subscription(
    request: Request,
    db: AsyncSession = Depends(get_db),
    token_data: dict = Depends(validate_token)
):
    """
    Save subscription receipt and verify with Apple.
    """
    logger.info("Received request for /subscription/save endpoint.")
    try:
        # Step 1: Authorization check
        if token_data.get('code') != 200:
            logger.warning(f"Unauthorized access attempt to /subscription/save. Message: {token_data.get('message', 'N/A')}")
            return custom_response(code=token_data.get('code', 500), message=token_data.get('message', 'Unauthorized'))

        user_id = token_data.get('user_id')
        user_device_id = token_data.get('user_device_id')
        device_type = token_data.get('device_type')

        current_date = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        if not user_device_id:
            logger.warning("User ID not found in token for subscription save request.")
            return custom_response(code=404, message="User not found or not authenticated")

        # Step 2: Read raw encrypted data
        try:
            encrypted_data = await request.body()
            logger.debug(f"Encrypted request body: {encrypted_data}")
        except Exception as e:
            logger.error(f"Failed to read request body for /subscription/save: {str(e)}", exc_info=True)
            return custom_response(code=400, message=f"Failed to read request body: {str(e)}")

        # Step 3: Decrypt data
        decrypted_data = decrypt_data(encrypted_data)
        logger.debug(f"Decrypted data: {decrypted_data}")

        # Step 4: Parse decrypted JSON and validate schema
        try:
            decrypted_json = decrypted_data
            params = SaveSubscriptionRequest.model_validate(decrypted_json)
            logger.info(f"Successfully parsed and validated payload for /subscription/save: {params}")
        except json.JSONDecodeError:
            logger.warning(f"Invalid JSON after decryption for /subscription/save. Decrypted data: {decrypted_data}")
            return custom_response(code=400, message="Invalid JSON after decryption")
        except ValidationError as ve:
            logger.warning(f"Validation failed for /subscription/save request. Errors: {ve.errors()}")
            return custom_response(code=422, data=ve.errors(), message="Validation failed")

        # Step 6: Verify receipt with Apple (advanced logic)
        secret = settings.secret
        print('device_type========',device_type)
        if device_type == 'I':
            user_subscriptions = await get_latest_receipt(params.receipt, secret)
        else:
            user_subscriptions = await get_latest_receipt_android(params.receipt, params.productId, user_id)

        # print(f"Latest subscription response for user {user_id}: {user_subscriptions}")
        logger.info(f"Latest subscription response for user {user_id}: {user_subscriptions}")
        
        latest_subscription = None

        if not isinstance(user_subscriptions, list):
                return custom_response(code=400, message="Invalid response format")

        # Group unique original_transaction_ids
        original_transaction_ids = list({r["original_transaction_id"] for r in user_subscriptions})

        latest_receipts = []
        for original_txn_id in original_transaction_ids:
            print('into original_transaction_ids')
            transactions = [row for row in user_subscriptions if row["original_transaction_id"] == original_txn_id]

            for row in transactions:
                print('into transactions')
                row["expires_date_ms"] = float(row.get("expires_date_ms", 0))

            if transactions:
                print('into transactions2')
                latest_expiration = max([t["expires_date_ms"] for t in transactions])
                latest_txn = next(t for t in transactions if t["expires_date_ms"] == latest_expiration)
                latest_receipts.append(latest_txn)


        for latest_receipt in latest_receipts:
            print('into latest_receipts')
            product_id = latest_receipt["product_id"]
            original_transaction_id = latest_receipt["original_transaction_id"]
            transaction_id = latest_receipt["transaction_id"]

            if device_type == 'I':
                print('into IOS')
                if product_id in ios_plans:
                    # latest_receipt["expires_date_ms"] = 1756199589000
                    # Check if subscription is still valid
                    if latest_receipt.get("expires_date_ms", 0) > time.time() * 1000:
                        sso = await verify_subscription(ios_plans,latest_receipt,db,token_data,params.receipt,user_id)
                        if sso.get('code') != 200:
                            return custom_response(code=400, message=sso.get("message", "Failed to verify subscription for ios"))
                        
                    else:
                        return custom_response(
                            code=400,
                            message=f"Subscription for product {product_id} has expired (ios).",
                    )

            elif device_type == 'A':
                if product_id in android_plans:
                    # latest_receipt["expires_date_ms"] = 1756822614000
                    # Check if subscription is still valid
                    print(latest_receipt.get("expires_date_ms", 0))
                    if latest_receipt.get("expires_date_ms", 0) > time.time() * 1000:
                        sso = await verify_subscription(android_plans,latest_receipt,db,token_data,params.receipt,user_id)
                        if sso.get('code') != 200:
                            return custom_response(code=400, message=sso.get("message", "Failed to verify subscription for android"))
                        
                    else:
                        return custom_response(
                            code=400,
                            message=f"Subscription for product {product_id} has expired (android).",
                        )
                    print('----------elif',android_plans)
            else:
                return custom_response(code=400, message="Device Type is missing")

        print('===============sub response============')
        
        return custom_response(
            code=200,
            data = {"have_active_subscription":True},
            message="Subscription receipt saved and verified.",
        )

    except Exception as e:
        await db.rollback()
        logger.error(f"Error saving subscription receipt: {str(e)}", exc_info=True)
        return custom_response(code=500, message=f"Internal server error: {str(e)}")

# --- Helper function stubs (implement as per your models/ORM) ---
async def get_device_by_user_id(user_id, db):
    # Return device ORM object for user_id
    pass

async def get_user_by_id(user_id, db):
    # Return user ORM object for user_id
    pass

async def update_user_gold_status(user, is_gold, validity_ms, starts_at_ms):
    # Update user gold status and validity
    pass

async def upsert_subscription_receipt(user, latest_receipt, device_type, receipt, is_expired):
    # Insert or update SubscriptionReceipt record
    pass

async def filter_group_wise_latest_subscriptions(receipt, user_id):
    # Validate receipt and group subscriptions as in your previous logic
    # Return dict like {"basic": {...}, "pro_plus": {...}, ...}
    pass

async def get_date_from_millisecond(ms: int) -> datetime:
    """Convert milliseconds since epoch to naive Python datetime (no timezone)."""
    return datetime.fromtimestamp(ms / 1000.0)