"""
API routes for KPI Analysis Application
"""

from fastapi import APIRouter, HTTPException, Depends, UploadFile, File, BackgroundTasks, status, Form, Request
from fastapi.responses import FileResponse, JSONResponse
from fastapi.security import OAuth2PasswordBearer
from pydantic import BaseModel
from typing import List, Optional
import aiofiles
import os
import shutil
from datetime import datetime
import json
from pathlib import Path
import logging

# Import application modules
from app.core.database import log_action
from app.core.auth import get_current_active_user, auth_manager, UserSession
from app.services.nextcloud_service import nextcloud_service
from app.services.excel_parser import excel_parser
from app.services.analysis_engine import analysis_engine
from app.services.pdf_generator import pdf_generator
from app.models import kpi_models
from config.settings import settings

# Login request model
class LoginRequest(BaseModel):
    username: str
    password: str

logger = logging.getLogger(__name__)

router = APIRouter()

# Authentication endpoints
@router.post("/auth/login")
async def login(
    login_request: LoginRequest, 
    request: Request = None
):
    """Authenticate user with LDAP/Active Directory and check group membership"""
    username = None
    try:
        username = login_request.username
        password = login_request.password
        
        logger.info(f"Login attempt for user: {username}")
        
        if not username or not password:
            logger.warning(f"Login attempt with missing credentials")
            raise HTTPException(
                status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
                detail="Username and password are required"
            )
        
        # Log incoming cookies for debugging cookie conflicts
        if request and hasattr(request, 'cookies'):
            conflicting_cookies = []
            odoo_cookie_names = ['session_id', 'frontend_lang', 'cids', 'tz']
            for cookie_name in request.cookies.keys():
                if cookie_name in odoo_cookie_names:
                    conflicting_cookies.append(cookie_name)
            
            if conflicting_cookies:
                logger.warning(f"Conflicting cookies detected: {conflicting_cookies}")
                logger.info(f"All incoming cookies: {list(request.cookies.keys())}")
        
        from ..core.auth import auth_manager
        from config.settings import settings
        
        # Log authentication configuration
        logger.info(f"Authentication config - LDAP: {bool(settings.ldap_server)}, Fallback: {settings.enable_fallback_auth}")
        
        # Authenticate with LDAP/fallback
        user_data = auth_manager.authenticate_user(username, password)
        
        if not user_data:
            logger.warning(f"Authentication failed for user {username}")
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Invalid credentials or user not authorized",
                headers={"WWW-Authenticate": "Bearer"},
            )
        
        logger.info(f"User {username} authenticated via {user_data.get('authentication_method', 'unknown')}")
        
        # Create session token
        token = auth_manager.create_access_token(user_data)
        logger.info(f"Access token created for user {username}")
        
        # Create response with proper headers to clear conflicting cookies
        response_data = {
            "success": True,
            "message": "Authentication successful",
            "access_token": token,
            "token_type": "bearer",
            "user": {
                "username": user_data["username"],
                "email": user_data["email"],
                "full_name": user_data["full_name"],
                "role": user_data["role"]
            }
        }
        
        # Import Response for setting headers
        from fastapi.responses import JSONResponse
        
        # Create response to clear conflicting cookies
        response = JSONResponse(content=response_data)
        
        # Clear common conflicting cookies that might come from other applications
        conflicting_cookie_names = [
            'session_id', 'frontend_lang', '_ga', '_ga_NMT50XL57M', 'cids', 'tz'
        ]
        
        for cookie_name in conflicting_cookie_names:
            response.set_cookie(
                key=cookie_name,
                value="",
                max_age=0,
                expires=0,
                path="/",
                domain=None,
                secure=False,
                httponly=False,
                samesite="lax"
            )
        
        logger.info(f"Login successful for user {username} - response sent")
        return response
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Login error for user {username if username else 'unknown'}: {e}", exc_info=True)
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Authentication service error: {str(e)}"
        )

@router.post("/auth/login-form")
async def login_form(
    username: str = Form(..., description="Username"),
    password: str = Form(..., description="Password"),
    request: Request = None
):
    """Form-based login endpoint for web forms"""
    try:
        if not username or not password:
            raise HTTPException(
                status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
                detail="Username and password are required"
            )
        
        # Log incoming cookies for debugging cookie conflicts
        if request and hasattr(request, 'cookies'):
            conflicting_cookies = []
            odoo_cookie_names = ['session_id', 'frontend_lang', 'cids', 'tz']
            for cookie_name in request.cookies.keys():
                if cookie_name in odoo_cookie_names:
                    conflicting_cookies.append(cookie_name)
            
            if conflicting_cookies:
                logger.warning(f"Form login - conflicting cookies detected: {conflicting_cookies}")
        
        from ..core.auth import auth_manager
        
        # Authenticate with LDAP/fallback
        user_data = auth_manager.authenticate_user(username, password)
        
        if not user_data:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Invalid credentials or user not authorized"
            )
        
        # Create session token
        token = auth_manager.create_access_token(user_data)
        
        # Create response with proper headers to clear conflicting cookies
        response_data = {
            "success": True,
            "message": "Authentication successful",
            "access_token": token,
            "token_type": "bearer",
            "user": {
                "username": user_data["username"],
                "email": user_data["email"],
                "full_name": user_data["full_name"],
                "role": user_data["role"]
            }
        }
        
        # Import Response for setting headers
        from fastapi.responses import JSONResponse
        
        # Create response to clear conflicting cookies
        response = JSONResponse(content=response_data)
        
        # Clear common conflicting cookies that might come from other applications
        conflicting_cookie_names = [
            'session_id', 'frontend_lang', '_ga', '_ga_NMT50XL57M', 'cids', 'tz'
        ]
        
        for cookie_name in conflicting_cookie_names:
            response.set_cookie(
                key=cookie_name,
                value="",
                max_age=0,
                expires=0,
                path="/",
                domain=None,
                secure=False,
                httponly=False,
                samesite="lax"
            )
        
        logger.info(f"Form login - User {username} authenticated successfully - cookies cleared")
        return response
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Form login error for user {username}: {e}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Authentication service error"
        )

@router.post("/auth/logout")
async def logout(current_user: dict = Depends(get_current_active_user)):
    """Logout user and invalidate session"""
    try:
        await UserSession.end_session(current_user["user_id"])
        return {
            "success": True,
            "message": "Logout successful"
        }
    except Exception as e:
        logger.error(f"Logout error: {e}")
        return {
            "success": True,
            "message": "Logout completed"
        }

@router.get("/auth/me")
async def get_current_user_info(current_user: dict = Depends(get_current_active_user)):
    """Get current user information"""
    return {
        "success": True,
        "user": {
            "username": current_user["username"],
            "email": current_user["email"],
            "full_name": current_user.get("full_name"),
            "role": current_user["role"],
            "authenticated_at": current_user.get("authenticated_at")
        }
    }

@router.get("/auth/test")
async def test_ldap_connection():
    """Test LDAP configuration and connection"""
    try:
        from ..services.ldap_auth_service import ldap_auth_service
        
        # Test connection
        connection_ok, connection_msg = ldap_auth_service.test_connection()
        
        # Test group access
        group_ok, group_msg = ldap_auth_service.test_group_access()
        
        return {
            "success": True,
            "ldap_configured": bool(settings.ldap_server),
            "fallback_auth_enabled": settings.enable_fallback_auth,
            "connection_test": {
                "success": connection_ok,
                "message": connection_msg
            },
            "group_test": {
                "success": group_ok,
                "message": group_msg,
                "group_dn": settings.ldap_kpi_group_dn
            },
            "authentication_methods": {
                "ldap": {
                    "available": bool(settings.ldap_server),
                    "configured": connection_ok and group_ok,
                    "server": settings.ldap_server,
                    "group_dn": settings.ldap_kpi_group_dn
                },
                "fallback": {
                    "enabled": settings.enable_fallback_auth,
                    "username": settings.fallback_admin_username if settings.enable_fallback_auth else None,
                    "role": settings.fallback_admin_role if settings.enable_fallback_auth else None
                }
            }
        }
        
    except Exception as e:
        logger.error(f"Authentication test error: {e}")
        return {
            "success": False,
            "error": str(e),
            "ldap_configured": bool(settings.ldap_server),
            "fallback_auth_enabled": settings.enable_fallback_auth,
            "authentication_methods": {
                "ldap": {"available": False, "configured": False},
                "fallback": {"enabled": settings.enable_fallback_auth}
            }
        }

@router.get("/auth/nextcloud")
async def nextcloud_auth():
    """Initiate Nextcloud OAuth authentication"""
    auth_url = nextcloud_service.get_oauth_url()
    return {"auth_url": auth_url}

@router.get("/auth/nextcloud/callback")
async def nextcloud_callback(code: str):
    """Handle Nextcloud OAuth callback"""
    # TODO: Implement Nextcloud OAuth callback
    return {"success": True, "message": "Nextcloud OAuth callback received"}

# File management endpoints
@router.post("/files/upload")
async def upload_file(
    background_tasks: BackgroundTasks,
    file: UploadFile = File(...),
    current_user: dict = Depends(get_current_active_user)
):
    """Upload KPI Excel file and trigger analysis"""
    
    # Validate file
    if not file.filename.endswith(tuple(settings.allowed_file_extensions)):
        raise HTTPException(status_code=400, detail="Invalid file type. Only .xlsx and .xls files are allowed.")
    
    # Create upload directory if it doesn't exist
    upload_dir = Path(settings.upload_directory)
    upload_dir.mkdir(parents=True, exist_ok=True)
    
    # Save file with timestamp
    timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
    safe_filename = f"{timestamp}_{file.filename}"
    file_path = upload_dir / safe_filename
    
    try:
        # Save uploaded file
        async with aiofiles.open(file_path, 'wb') as buffer:
            content = await file.read()
            await buffer.write(content)
        
        # Get file size
        file_size = file_path.stat().st_size
        
        # Save file record to database
        from app.core.database import save_uploaded_file
        file_id = await save_uploaded_file(
            filename=file.filename,
            file_path=str(file_path),
            uploaded_by=current_user["user_id"],
            file_size=file_size
        )
        
        # Log upload action
        await log_action(current_user["user_id"], "FILE_UPLOAD", f"Uploaded {file.filename}")
        
        # Trigger background analysis
        background_tasks.add_task(process_excel_file, str(file_path), current_user["user_id"], file_id)
        
        return {
            "success": True,
            "message": "File uploaded successfully. Analysis started in background.",
            "file_id": file_id,
            "file_path": str(file_path),
            "filename": file.filename
        }
        
    except Exception as e:
        logger.error(f"Error uploading file: {str(e)}")
        # Clean up file if it was created
        if file_path.exists():
            file_path.unlink()
        raise HTTPException(status_code=500, detail=f"Failed to upload file: {str(e)}")

@router.get("/files/list")
async def list_files(current_user: dict = Depends(get_current_active_user)):
    """List uploaded KPI files"""
    try:
        from app.core.database import get_uploaded_files
        files = await get_uploaded_files()
        
        return {
            "success": True,
            "files": files
        }
    except Exception as e:
        logger.error(f"Error listing files: {str(e)}")
        return {
            "success": True,
            "files": []
        }

@router.delete("/files/delete/{file_id}")
async def delete_file(file_id: int, current_user: dict = Depends(get_current_active_user)):
    """Delete uploaded file and its analysis results"""
    try:
        from app.core.database import delete_uploaded_file
        success = await delete_uploaded_file(file_id)
        
        if success:
            await log_action(current_user["user_id"], "FILE_DELETE", f"Deleted file ID {file_id}")
            return {
                "success": True,
                "message": "File deleted successfully"
            }
        else:
            raise HTTPException(status_code=404, detail="File not found")
            
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Error deleting file: {str(e)}")
        raise HTTPException(status_code=500, detail=f"Failed to delete file: {str(e)}")

# Nextcloud integration endpoints
@router.get("/nextcloud/files")
async def list_nextcloud_files(
    folder_path: str = settings.nextcloud_kpi_folder,
    current_user: dict = Depends(get_current_active_user)
):
    """List files from Nextcloud KPI folder"""
    try:
        files = await nextcloud_service.list_files(folder_path)
        return {"files": files}
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Failed to list Nextcloud files: {str(e)}")

@router.post("/nextcloud/download/{file_id}")
async def download_nextcloud_file(
    file_id: str,
    background_tasks: BackgroundTasks,
    current_user: dict = Depends(get_current_active_user)
):
    """Download file from Nextcloud"""
    try:
        # Download file
        file_content = nextcloud_service.download_file(file_id)
        
        # Save locally
        filename = f"downloaded_{file_id}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx"
        file_path = Path(settings.upload_directory) / filename
        
        async with aiofiles.open(file_path, 'wb') as f:
            await f.write(file_content)
        
        # Schedule background processing
        background_tasks.add_task(process_excel_file, str(file_path), current_user["user_id"], file_id)
        
        await log_action(current_user["user_id"], "NEXTCLOUD_DOWNLOAD", f"Downloaded file {file_id}")
        
        return {
            "success": True,
            "message": "File downloaded and queued for processing",
            "file_path": str(file_path),
            "filename": filename
        }
        
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Failed to download file: {str(e)}")

# Analysis endpoints
@router.post("/analysis/run/{file_id}")
async def run_analysis(
    file_id: int,
    background_tasks: BackgroundTasks,
    current_user: dict = Depends(get_current_active_user)
):
    """Run KPI analysis on uploaded file"""
    try:
        # Get file path from database
        from config.settings import settings
        from pathlib import Path
        import aiosqlite
        
        db_path = Path(settings.database_url.replace("sqlite:///", ""))
        async with aiosqlite.connect(db_path) as db:
            db.row_factory = aiosqlite.Row
            cursor = await db.execute("SELECT file_path FROM kpi_files WHERE id = ?", (file_id,))
            row = await cursor.fetchone()
            
            if not row:
                raise HTTPException(status_code=404, detail="File not found")
            
            file_path = row['file_path']
        
        background_tasks.add_task(process_excel_file, file_path, current_user["user_id"], file_id)
        return {"success": True, "message": "Analysis started in background"}
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Error starting analysis: {str(e)}")
        raise HTTPException(status_code=500, detail=f"Failed to start analysis: {str(e)}")

@router.get("/analysis/{file_id}")
async def get_analysis_results_endpoint(file_id: int, current_user: dict = Depends(get_current_active_user)):
    """Get analysis results for a file"""
    try:
        from app.core.database import get_analysis_results
        results = await get_analysis_results(file_id)
        
        if not results:
            raise HTTPException(status_code=404, detail="Analysis results not found. File may not be processed yet.")
        
        return {
            "success": True,
            "file_id": file_id,
            "total_score": results['total_score'],
            "perspective_scores": results['perspective_scores'],
            "achievements": results['achievements'],
            "recommendations": results['recommendations'],
            "charts_generated": True,
            "report_generated": bool(results['report_path'])
        }
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Error retrieving analysis results: {str(e)}")
        raise HTTPException(status_code=500, detail=f"Failed to retrieve analysis results: {str(e)}")

@router.get("/analysis/{file_id}/charts")
async def get_analysis_charts(file_id: int, current_user: dict = Depends(get_current_active_user)):
    """Get interactive charts data"""
    try:
        from app.core.database import get_analysis_results
        results = await get_analysis_results(file_id)
        
        if not results:
            return {"charts": []}
        
        # Get perspective scores
        perspective_scores = results.get('perspective_scores', {})
        
        if not perspective_scores:
            return {"charts": []}
        
        # Create chart data from actual analysis results
        charts = []
        
        # Chart 1: Perspective scores
        if perspective_scores:
            charts.append({
                "type": "score_breakdown",
                "title": "KPI Score Breakdown by Perspective",
                "data": perspective_scores
            })
        
        # Chart 2: Achievement status
        achievements = results.get('achievements', {})
        if achievements:
            charts.append({
                "type": "achievement_status",
                "title": "KPI Achievement Status",
                "data": achievements
            })
        
        return {"charts": charts}
        
    except Exception as e:
        logger.error(f"Error getting charts: {str(e)}")
        return {"charts": []}

@router.get("/analysis/{file_id}/report")
async def download_report(file_id: int, current_user: dict = Depends(get_current_active_user)):
    """Download PDF report"""
    try:
        from app.core.database import get_analysis_results
        results = await get_analysis_results(file_id)
        
        if not results:
            raise HTTPException(status_code=404, detail="Analysis results not found")
        
        report_path = results.get('report_path')
        
        if not report_path or not Path(report_path).exists():
            raise HTTPException(status_code=404, detail="PDF report not found. It may not have been generated yet.")
        
        # Get filename from path
        filename = Path(report_path).name
        
        return FileResponse(
            path=str(report_path),
            filename=filename,
            media_type="application/pdf"
        )
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Error downloading report: {str(e)}")
        raise HTTPException(status_code=500, detail=f"Failed to download report: {str(e)}")

# Background task functions
async def process_excel_file(file_path: str, user_id: int, file_id: int):
    """Background task to process Excel file"""
    try:
        logger.info(f"Starting analysis for file: {file_path}")
        
        # Verify file exists
        if not os.path.exists(file_path):
            raise FileNotFoundError(f"File not found: {file_path}")
        
        # Parse Excel file
        kpi_data = await excel_parser.parse_excel_file(file_path)
        logger.info(f"Excel file parsed successfully: {len(kpi_data.kpi_sheets)} KPI sheets found")
        
        # Validate parsed data
        if not kpi_data.kpi_sheets:
            logger.warning(f"No KPI sheets found in file {file_path}")
        
        # Run analysis
        analysis_results = await analysis_engine.analyze_kpi_data(kpi_data)
        logger.info(f"Analysis completed with score: {analysis_results.total_score}")
        
        # Generate charts
        charts = await analysis_engine.generate_charts(kpi_data, analysis_results)
        logger.info(f"Generated {len(charts)} charts")
        
        # Generate PDF report
        try:
            report_path = await pdf_generator.generate_report(kpi_data, analysis_results)
            if report_path:
                logger.info(f"PDF report generated: {report_path}")
            else:
                logger.warning("PDF report generation returned empty path")
                report_path = ""
        except Exception as pdf_error:
            logger.error(f"PDF generation failed: {str(pdf_error)}", exc_info=True)
            report_path = ""
        
        # Save analysis results to database
        from app.core.database import save_analysis_results
        await save_analysis_results(
            file_id=file_id,
            total_score=analysis_results.total_score,
            perspective_scores=analysis_results.perspective_scores,
            achievements=analysis_results.achievements,
            recommendations=analysis_results.recommendations,
            report_path=report_path
        )
        logger.info(f"Analysis results saved to database for file ID {file_id}")
        
        # Mark file as processed
        from app.core.database import mark_file_processed
        await mark_file_processed(file_id)
        logger.info(f"File ID {file_id} marked as processed")
        
        await log_action(user_id, "ANALYSIS_COMPLETE", f"Analysis completed for file ID {file_id}")
        logger.info(f"Analysis workflow completed successfully for file ID {file_id}")
        
    except Exception as e:
        logger.error(f"Analysis failed for {file_path}: {str(e)}", exc_info=True)
        await log_action(user_id, "ANALYSIS_ERROR", f"Analysis failed: {str(e)}")
        
        # Try to mark file as processed even if analysis failed
        try:
            from app.core.database import mark_file_processed
            await mark_file_processed(file_id)
        except:
            pass

# Utility endpoints
@router.get("/health")
async def health_check():
    """Health check endpoint"""
    return {
        "status": "healthy",
        "service": "KPI Analysis API",
        "timestamp": datetime.now().isoformat(),
        "nextcloud_configured": bool(settings.nextcloud_oauth_client_id),
        "openai_configured": bool(settings.openai_api_key)
    }

@router.get("/config/status")
async def config_status():
    """Check configuration status"""
    return {
        "nextcloud": {
            "configured": bool(settings.nextcloud_oauth_client_id),
            "base_url": settings.nextcloud_base_url,
            "folder": settings.nextcloud_kpi_folder
        },
        "openai": {
            "configured": bool(settings.openai_api_key),
            "model": settings.openai_model
        },
        "ldap": {
            "configured": bool(settings.ldap_server),
            "server": settings.ldap_server
        }
    }