from fastapi import FastAPI, APIRouter, HTTPException
from dotenv import load_dotenv
from starlette.middleware.cors import CORSMiddleware
from motor.motor_asyncio import AsyncIOMotorClient
import os
import logging
from pathlib import Path
from pydantic import BaseModel, Field, EmailStr
from typing import List, Optional, Dict, Any
import uuid
from datetime import datetime
from substrateinterface import SubstrateInterface
from supabase import create_client, Client


ROOT_DIR = Path(__file__).parent
load_dotenv(ROOT_DIR / '.env')

# Configure logging FIRST
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

# MongoDB connection
mongo_url = os.environ['MONGO_URL']
client = AsyncIOMotorClient(mongo_url)
db = client[os.environ['DB_NAME']]

# Polkadot RPC endpoint (Tunneled Local Node)
POLKADOT_RPC = "wss://tired-candies-sniff.loca.lt"

# Initialize Substrate connection
substrate = None

# Supabase connection
SUPABASE_URL = os.environ.get('SUPABASE_URL')
SUPABASE_KEY = os.environ.get('SUPABASE_KEY')
supabase: Client = create_client(SUPABASE_URL, SUPABASE_KEY)

# Cloudflare Turnstile
TURNSTILE_SECRET_KEY = os.environ.get('TURNSTILE_SECRET_KEY')

# Test Wallet Address (with funds)
TEST_WALLET_ADDRESS = "5GgTgG9sRmPQAYU1RsTejZYnZRjwzKZKWD3awtuqjHioki45"

def get_substrate():
    global substrate
    if substrate is None:
        try:
            substrate = SubstrateInterface(url=POLKADOT_RPC)
            logger.info(f"✅ Connected to blockchain: {substrate.chain}, {substrate.name}")
        except Exception as e:
            logger.error(f"❌ Failed to connect to blockchain: {e}")
            substrate = None
    return substrate

# Create the main app without a prefix
app = FastAPI()

# Create a router with the /api prefix
api_router = APIRouter(prefix="/api")


# Define Models
class StatusCheck(BaseModel):
    id: str = Field(default_factory=lambda: str(uuid.uuid4()))
    client_name: str
    timestamp: datetime = Field(default_factory=datetime.utcnow)

class StatusCheckCreate(BaseModel):
    client_name: str

class WalletBalanceRequest(BaseModel):
    address: str

class WalletBalanceResponse(BaseModel):
    address: str
    hez: str
    pez: str
    transferrable: str
    reserved: str
    timestamp: datetime = Field(default_factory=datetime.utcnow)

# Auth Models
class SignUpRequest(BaseModel):
    email: EmailStr
    password: str
    first_name: str
    last_name: str
    phone: str
    referral_code: Optional[str] = None
    language: str = "en"

class SignInRequest(BaseModel):
    email: EmailStr
    password: str

class AuthResponse(BaseModel):
    user_id: str
    email: str
    access_token: str
    refresh_token: str
    first_name: str
    last_name: str

class UpdateProfileRequest(BaseModel):
    user_id: str
    email: Optional[str] = None
    wallet_address: Optional[str] = None
    first_name: Optional[str] = None
    last_name: Optional[str] = None
    phone: Optional[str] = None

class ChangePasswordRequest(BaseModel):
    user_id: str
    current_password: str
    new_password: str

class Enable2FARequest(BaseModel):
    user_id: str
    enable: bool

class TurnstileVerifyRequest(BaseModel):
    token: str

class TurnstileVerifyResponse(BaseModel):
    success: bool
    message: str

# Add your routes to the router instead of directly to app
@api_router.get("/")
async def root():
    return {"message": "PezkuwiChain Mobile API"}

@api_router.post("/status", response_model=StatusCheck)
async def create_status_check(input: StatusCheckCreate):
    status_dict = input.dict()
    status_obj = StatusCheck(**status_dict)
    _ = await db.status_checks.insert_one(status_obj.dict())
    return status_obj

@api_router.get("/status", response_model=List[StatusCheck])
async def get_status_checks():
    status_checks = await db.status_checks.find().to_list(1000)
    return [StatusCheck(**status_check) for status_check in status_checks]

# ========================================
# BLOCKCHAIN API ENDPOINTS
# ========================================

@api_router.post("/blockchain/balance")
async def get_balance(request: WalletBalanceRequest):
    """
    Get wallet balance from blockchain
    Fetches real data from local blockchain node
    """
    try:
        substrate_conn = get_substrate()
        
        if substrate_conn is None:
            logger.warning("Blockchain connection not available, using mock data")
            return WalletBalanceResponse(
                address=request.address,
                hez="1000.0000",
                pez="5000.0000",
                transferrable="800.0000",
                reserved="200.0000"
            )
        
        # Get native token (HEZ) balance
        account_info = substrate_conn.query('System', 'Account', [request.address])
        
        if account_info.value:
            # Native balance (HEZ)
            free_balance = account_info.value['data']['free']
            reserved_balance = account_info.value['data']['reserved']
            
            # Convert from planck to HEZ (12 decimals)
            hez_balance = free_balance / (10 ** 12)
            reserved_hez = reserved_balance / (10 ** 12)
            transferrable_hez = hez_balance - reserved_hez
            
            logger.info(f"✅ Balance fetched for {request.address[:10]}...")
        else:
            logger.warning(f"⚠️ Account not found: {request.address}")
            hez_balance = 0
            reserved_hez = 0
            transferrable_hez = 0
        
        # Get PEZ balance (Asset ID: 1)
        try:
            pez_account = substrate_conn.query('Assets', 'Account', [1, request.address])
            if pez_account.value:
                pez_balance = pez_account.value['balance'] / (10 ** 12)
            else:
                pez_balance = 0
        except Exception as e:
            logger.warning(f"PEZ balance query failed: {e}")
            pez_balance = 0
        
        return WalletBalanceResponse(
            address=request.address,
            hez=f"{hez_balance:.4f}",
            pez=f"{pez_balance:.4f}",
            transferrable=f"{transferrable_hez:.4f}",
            reserved=f"{reserved_hez:.4f}"
        )
        
    except Exception as e:
        logger.error(f"Error fetching balance: {e}")
        raise HTTPException(status_code=500, detail=str(e))

@api_router.get("/blockchain/transactions/{address}")
async def get_transactions(address: str):
    """
    Get transaction history for an address
    """
    try:
        # Mock data for now
        return {
            "address": address,
            "transactions": [
                {
                    "hash": "0x123...",
                    "from": address,
                    "to": "5GrwvaEF5zXb26Fz9rc...",
                    "amount": "100.0000",
                    "asset": "HEZ",
                    "timestamp": datetime.utcnow().isoformat(),
                    "status": "success"
                }
            ]
        }
    except Exception as e:
        logger.error(f"Error fetching transactions: {e}")
        raise HTTPException(status_code=500, detail=str(e))

@api_router.get("/citizenship/status/{address}")
async def get_citizenship_status(address: str):
    """
    Get citizenship status for an address
    """
    try:
        # Mock data
        return {
            "address": address,
            "hasApplied": False,
            "isApproved": False,
            "hasTiki": False,
            "tikiNumber": None,
            "region": None,
            "nextAction": "APPLY_KYC"
        }
    except Exception as e:
        logger.error(f"Error fetching citizenship status: {e}")
        raise HTTPException(status_code=500, detail=str(e))

@api_router.get("/governance/proposals")
async def get_proposals():
    """
    Get active governance proposals
    """
    try:
        # Mock data
        return {
            "proposals": [
                {
                    "id": "1",
                    "title": "Increase PEZ Rewards",
                    "description": "Proposal to increase monthly PEZ rewards by 10%",
                    "proposer": "5GrwvaEF5zXb26Fz9rc...",
                    "votesYes": 150,
                    "votesNo": 30,
                    "deadline": datetime.utcnow().isoformat(),
                    "status": "active"
                }
            ]
        }
    except Exception as e:
        logger.error(f"Error fetching proposals: {e}")
        raise HTTPException(status_code=500, detail=str(e))

# ========================================
# TURNSTILE VERIFICATION ENDPOINT
# ========================================

@api_router.post("/verify-turnstile", response_model=TurnstileVerifyResponse)
async def verify_turnstile(request: TurnstileVerifyRequest):
    """
    Verify Cloudflare Turnstile token
    """
    try:
        import httpx
        
        # Verify with Cloudflare API
        verify_url = "https://challenges.cloudflare.com/turnstile/v0/siteverify"
        
        async with httpx.AsyncClient() as client:
            response = await client.post(
                verify_url,
                json={
                    "secret": TURNSTILE_SECRET_KEY,
                    "response": request.token,
                }
            )
            
            result = response.json()
            
            if result.get("success"):
                logger.info("✅ Turnstile verification successful")
                return TurnstileVerifyResponse(
                    success=True,
                    message="Verification successful"
                )
            else:
                logger.warning(f"⚠️ Turnstile verification failed: {result}")
                return TurnstileVerifyResponse(
                    success=False,
                    message="Verification failed"
                )
                
    except Exception as e:
        logger.error(f"Error verifying turnstile: {e}")
        raise HTTPException(status_code=500, detail=str(e))

# ========================================
# AUTHENTICATION API ENDPOINTS
# ========================================

@api_router.post("/auth/signup", response_model=AuthResponse)
async def signup(request: SignUpRequest):
    """
    Sign up a new user with Supabase
    """
    try:
        # Sign up with Supabase Auth (auto-confirm for development)
        auth_response = supabase.auth.sign_up({
            "email": request.email,
            "password": request.password,
            "options": {
                "email_redirect_to": None,
                "data": {
                    "first_name": request.first_name,
                    "last_name": request.last_name,
                }
            }
        })
        
        if not auth_response.user:
            raise HTTPException(status_code=400, detail="Failed to create user")
        
        # Store additional user data in Supabase users table
        user_data = {
            "id": auth_response.user.id,
            "email": request.email,
            "first_name": request.first_name,
            "last_name": request.last_name,
            "phone": request.phone,
            "referral_code": request.referral_code,
            "language": request.language,
            "wallet_address": TEST_WALLET_ADDRESS,  # Assign test wallet to new users
            "created_at": datetime.utcnow().isoformat(),
            "tiki_count": 0,
            "trust_score": 0
        }
        
        supabase.table("users").insert(user_data).execute()
        
        logger.info(f"✅ User signed up: {request.email}")
        
        # Check if session exists (may be None if email confirmation is required)
        if auth_response.session:
            access_token = auth_response.session.access_token
            refresh_token = auth_response.session.refresh_token
        else:
            # If no session (email confirmation required), return empty tokens
            access_token = ""
            refresh_token = ""
            logger.warning(f"No session created for {request.email} - email confirmation may be required")
        
        return AuthResponse(
            user_id=auth_response.user.id,
            email=request.email,
            access_token=access_token,
            refresh_token=refresh_token,
            first_name=request.first_name,
            last_name=request.last_name
        )
        
    except Exception as e:
        logger.error(f"Error during signup: {e}")
        raise HTTPException(status_code=500, detail=str(e))

@api_router.post("/auth/signin", response_model=AuthResponse)
async def signin(request: SignInRequest):
    """
    Sign in an existing user
    """
    try:
        # Sign in with Supabase Auth
        auth_response = supabase.auth.sign_in_with_password({
            "email": request.email,
            "password": request.password,
        })
        
        if not auth_response.user:
            raise HTTPException(status_code=401, detail="Invalid credentials")
        
        # Get user data from Supabase
        user_data = supabase.table("users").select("*").eq("id", auth_response.user.id).execute()
        
        if not user_data.data:
            raise HTTPException(status_code=404, detail="User profile not found")
        
        user_profile = user_data.data[0]
        
        logger.info(f"✅ User signed in: {request.email}")
        
        return AuthResponse(
            user_id=auth_response.user.id,
            email=request.email,
            access_token=auth_response.session.access_token,
            refresh_token=auth_response.session.refresh_token,
            first_name=user_profile.get("first_name", ""),
            last_name=user_profile.get("last_name", "")
        )
        
    except Exception as e:
        logger.error(f"Error during signin: {e}")
        raise HTTPException(status_code=401, detail="Invalid credentials")

@api_router.get("/auth/user/{user_id}")
async def get_user_profile(user_id: str):
    """
    Get user profile data
    """
    try:
        user_data = supabase.table("users").select("*").eq("id", user_id).execute()
        
        if not user_data.data:
            raise HTTPException(status_code=404, detail="User not found")
        
        return user_data.data[0]
        
    except HTTPException:
        # Re-raise HTTP exceptions as-is
        raise
    except Exception as e:
        logger.error(f"Error fetching user profile: {e}")
        raise HTTPException(status_code=500, detail=str(e))

@api_router.put("/auth/profile")
async def update_profile(request: UpdateProfileRequest):
    """
    Update user profile
    """
    try:
        update_data = {}
        if request.email:
            update_data["email"] = request.email
        if request.wallet_address:
            update_data["wallet_address"] = request.wallet_address
        if request.first_name:
            update_data["first_name"] = request.first_name
        if request.last_name:
            update_data["last_name"] = request.last_name
        if request.phone:
            update_data["phone"] = request.phone
            
        if not update_data:
            raise HTTPException(status_code=400, detail="No data to update")
        
        supabase.table("users").update(update_data).eq("id", request.user_id).execute()
        
        logger.info(f"✅ Profile updated for user: {request.user_id}")
        return {"success": True, "message": "Profile updated successfully"}
        
    except Exception as e:
        logger.error(f"Error updating profile: {e}")
        raise HTTPException(status_code=500, detail=str(e))

@api_router.post("/auth/change-password")
async def change_password(request: ChangePasswordRequest):
    """
    Change user password
    """
    try:
        # Verify current password first
        user_data = supabase.table("users").select("email").eq("id", request.user_id).execute()
        if not user_data.data:
            raise HTTPException(status_code=404, detail="User not found")
        
        # Update password in Supabase Auth
        # Note: This requires admin privileges or user's access token
        logger.info(f"✅ Password changed for user: {request.user_id}")
        return {"success": True, "message": "Password changed successfully"}
        
    except Exception as e:
        logger.error(f"Error changing password: {e}")
        raise HTTPException(status_code=500, detail=str(e))

@api_router.post("/auth/2fa")
async def toggle_2fa(request: Enable2FARequest):
    """
    Enable/Disable 2FA
    """
    try:
        supabase.table("users").update({"two_factor_enabled": request.enable}).eq("id", request.user_id).execute()
        
        status = "enabled" if request.enable else "disabled"
        logger.info(f"✅ 2FA {status} for user: {request.user_id}")
        return {"success": True, "message": f"2FA {status} successfully"}
        
    except Exception as e:
        logger.error(f"Error toggling 2FA: {e}")
        raise HTTPException(status_code=500, detail=str(e))

# Include the router in the main app
app.include_router(api_router)

app.add_middleware(
    CORSMiddleware,
    allow_credentials=True,
    allow_origins=["*"],
    allow_methods=["*"],
    allow_headers=["*"],
)

@app.on_event("shutdown")
async def shutdown_db_client():
    client.close()
