from fastapi import APIRouter, Depends, HTTPException, Query, File, UploadFile, Request
from sqlalchemy.orm import Session
from typing import Optional
from app.dependencies import get_db2, get_db3
from app.utils.dependencies import get_current_user
from app.utils.logging import logger

from app.schemas import checkin_ftth_new as schemas
from app.services.checkin_service_new import CheckinService
import random
import time
from app.utils.redis_helper import store_otp, verify_and_delete_otp
from app.utils.notification import send_whatsapp_otp
from app.utils.rate_limiter import limiter
router = APIRouter(prefix="/checkin-ftth", tags=["Checkin FTTH New"])


@router.post("/send-otp", status_code=200)
@limiter.limit("3/minute")
async def request_otp(
    request: Request,
    payload: schemas.RequestOTPPayload,
    dependencies=Depends(get_current_user)
):
    username = dependencies.username
    try:
        # Generate 4 digit angka OTP acak
        otp_code = f"{random.randint(1000, 9999)}"
        
        # Simpan OTP ke Redis (kedaluwarsa 5 menit / 300 detik)
        store_otp(payload.nomor_pelanggan, otp_code, ttl_seconds=300)
        
        # Kirim OTP ke WhatsApp pelanggan
        success = await send_whatsapp_otp(payload.nomor_pelanggan, otp_code)
        
        if not success:
            raise HTTPException(status_code=500, detail="Gagal mengirimkan OTP. Silakan periksa nomor telepon.")
            
        return {
            "meta": {
                "status_code": 200,
                "success": True,
                "message": "OTP berhasil dikirim ke nomor pelanggan."
            }
        }
    except Exception as e:
        logger.error(f"error request otp: {e}", extra={"username": username}, exc_info=True)
        raise HTTPException(status_code=500, detail="Error: internal server error")


@router.post(
    "/pelanggan",
    response_model=schemas.PelangganResponse,
    status_code=201
)
async def create_pelanggan(
    form_data: schemas.PelangganCreate = Depends(schemas.PelangganCreate.as_form),
    db3: Session = Depends(get_db3),
    dependencies=Depends(get_current_user)
):
    username = dependencies.username
    try:
        # 1. Verifikasi dan Hapus OTP dari Redis
        is_valid = verify_and_delete_otp(form_data.nomor_pelanggan, form_data.otp_code)
        if not is_valid:
            raise HTTPException(
                status_code=400, 
                detail="Kode OTP tidak valid atau sudah kedaluwarsa. Silakan minta kode baru."
            )
            
        # 2. Proses pembuatan data pelanggan jika OTP valid
        data = form_data.model_dump(exclude={"otp_code"})
        result = CheckinService.create_pelanggan_record(db3, data, username)
        
        return schemas.PelangganResponse(
            data=result,
            meta={
                "status_code": 201,
                "success": True,
                "message": "Successfully created customer activity data and verified OTP"
            }
        )
    except HTTPException as he:
        raise he
    except Exception as e:
        logger.error(f"error : {e}", extra={"username": username}, exc_info=True)
        raise HTTPException(status_code=500, detail="Error: internal server error")

@router.get(
    "/history",
    response_model=schemas.HistoryListResponse
)
async def get_history(
    db3: Session = Depends(get_db3),
    dependencies=Depends(get_current_user)
):
    username = dependencies.username
    try:
        history = CheckinService.get_history_list(db3, username)
        
        return schemas.HistoryListResponse(
            data=history,
            meta={
                "status_code": 200,
                "success": True,
                "message": "Successfully retrieved checkin history"
            }
        )
    except Exception as e:
        logger.error(f"error : {e}", extra={"username": username}, exc_info=True)
        raise HTTPException(status_code=500, detail="Error: internal server error")


@router.get(
    "/pending/{no_activity}",
    response_model=schemas.PelangganResponse
)
async def get_pending_detail(
    no_activity: str,
    db3: Session = Depends(get_db3),
    dependencies=Depends(get_current_user)
):
    username = dependencies.username
    try:
        result = CheckinService.get_pending_detail(db3, no_activity, username)
        
        return schemas.PelangganResponse(
            data=result,
            meta={
                "status_code": 200,
                "success": True,
                "message": "Successfully retrieved pending activity details"
            }
        )
    except ValueError as ve:
        logger.error(f"error : {ve}", extra={"username": username})
        raise HTTPException(status_code=404, detail=str(ve))
    except Exception as e:
        logger.error(f"error : {e}", extra={"username": username}, exc_info=True)
        raise HTTPException(status_code=500, detail="Error: internal server error")


@router.post(
    "/submit",
    response_model=schemas.CheckinFtthResponse,
    status_code=201
)
async def submit_checkin(
    form_data: schemas.CheckinFtthCreate = Depends(schemas.CheckinFtthCreate.as_form),
    db2: Session = Depends(get_db2),
    db3: Session = Depends(get_db3),
    dependencies=Depends(get_current_user)
):
    username = dependencies.username
    try:
        # Extract form2 fields except uploaded file
        form2_data = form_data.model_dump(exclude={"foto_fat"})
        
        # Process service logic
        result = await CheckinService.create_checkin_from_form2(
            db3=db3,
            db2=db2,
            no_activity=form_data.no_activity,
            kode_sales=username,
            form2_data=form2_data,
            foto_fat=form_data.foto_fat
        )
        
        return schemas.CheckinFtthResponse(
            data=result,
            meta={
                "status_code": 201,
                "success": True,
                "message": "Successfully submitted checkin data"
            }
        )
    except ValueError as ve:
        logger.error(f"error : {ve}", extra={"username": username})
        raise HTTPException(status_code=400, detail=str(ve))
    except Exception as e:
        logger.error(f"error : {e}", extra={"username": username}, exc_info=True)
        raise HTTPException(status_code=500, detail="Error: internal server error")


@router.post(
    "/submit-new-fat",
    response_model=schemas.SubmitNewFatResponse,
    status_code=201
)
async def submit_new_fat(
    form_data: schemas.SubmitNewFatRequest = Depends(schemas.SubmitNewFatRequest.as_form),
    db3: Session = Depends(get_db3),
    dependencies=Depends(get_current_user)
):
    username = dependencies.username
    try:
        data = form_data.model_dump()
        result = CheckinService.submit_new_fat(
            db3=db3,
            no_activity=form_data.no_activity,
            kode_sales=username,
            payload_data=data
        )
        
        return schemas.SubmitNewFatResponse(
            data=result,
            meta={
                "status_code": 201,
                "success": True,
                "message": "Successfully submitted new FAT and checkin data"
            }
        )
    except ValueError as ve:
        logger.error(f"error : {ve}", extra={"username": username})
        raise HTTPException(status_code=400, detail=str(ve))
    except Exception as e:
        logger.error(f"error : {e}", extra={"username": username}, exc_info=True)
        raise HTTPException(status_code=500, detail="Error: internal server error")


@router.post(
    "/join-new-fat",
    response_model=schemas.SubmitNewFatResponse,
    status_code=201
)
async def join_new_fat(
    form_data: schemas.JoinNewFatRequest = Depends(schemas.JoinNewFatRequest.as_form),
    db3: Session = Depends(get_db3),
    dependencies=Depends(get_current_user)
):
    username = dependencies.username
    try:
        result = CheckinService.join_new_fat(
            db3=db3,
            no_activity=form_data.no_activity,
            kode_sales=username,
            fat_code=form_data.fat_code,
            status_pemesanan=form_data.status_pemesanan
        )
        
        return schemas.SubmitNewFatResponse(
            data=result,
            meta={
                "status_code": 201,
                "success": True,
                "message": "Successfully joined new FAT and checkin data"
            }
        )
    except ValueError as ve:
        logger.error(f"error : {ve}", extra={"username": username})
        raise HTTPException(status_code=400, detail=str(ve))
    except Exception as e:
        logger.error(f"error : {e}", extra={"username": username}, exc_info=True)
        raise HTTPException(status_code=500, detail="Error: internal server error")


@router.get(
    "/fat-baru/nearby",
    response_model=schemas.FatBaruNearbyListResponse
)
@limiter.limit("30/minute")
async def get_nearby_fat_baru(
    request: Request,
    latitude: float = Query(..., description="Latitude posisi user"),
    longitude: float = Query(..., description="Longitude posisi user"),
    radius: float = Query(5.0, description="Batas jarak dalam kilometer (default 5.0)"),
    db3: Session = Depends(get_db3),
    dependencies=Depends(get_current_user)
):
    username = dependencies.username
    try:
        fats = CheckinService.get_nearby_fat_baru(db3, latitude, longitude, max_radius_km=radius)
        
        return schemas.FatBaruNearbyListResponse(
            data=fats,
            meta={
                "status_code": 200,
                "success": True,
                "message": "Successfully retrieved nearby FAT Baru data (radius 5 KM)"
            }
        )
    except Exception as e:
        logger.error(f"error : {e}", extra={"username": username}, exc_info=True)
        raise HTTPException(status_code=500, detail="Error: internal server error")
@router.get(
    "/fat-baru/{fat_code}",
    response_model=schemas.FatBaruDetailResponse
)
async def get_fat_baru_detail(
    fat_code: str,
    db3: Session = Depends(get_db3),
    dependencies=Depends(get_current_user)
):
    username = dependencies.username
    try:
        fat_detail = CheckinService.get_fat_baru_detail(db3, fat_code)
        
        return schemas.FatBaruDetailResponse(
            data=fat_detail,
            meta={
                "status_code": 200,
                "success": True,
                "message": "Successfully retrieved FAT Baru detail"
            }
        )
    except ValueError as ve:
        logger.error(f"error : {ve}", extra={"username": username})
        raise HTTPException(status_code=404, detail=str(ve))
    except Exception as e:
        logger.error(f"error : {e}", extra={"username": username}, exc_info=True)
        raise HTTPException(status_code=500, detail="Error: internal server error")


@router.get(
    "/done/{no_activity}",
    response_model=schemas.CheckinFtthResponse
)
async def get_done_detail(
    no_activity: str,
    db3: Session = Depends(get_db3),
    dependencies=Depends(get_current_user)
):
    username = dependencies.username
    try:
        result = CheckinService.get_done_detail(db3, no_activity, username)
        
        return schemas.CheckinFtthResponse(
            data=result,
            meta={
                "status_code": 200,
                "success": True,
                "message": "Successfully retrieved completed checkin details"
            }
        )
    except ValueError as ve:
        logger.error(f"error : {ve}", extra={"username": username})
        raise HTTPException(status_code=404, detail=str(ve))
    except Exception as e:
        logger.error(f"error : {e}", extra={"username": username}, exc_info=True)
        raise HTTPException(status_code=500, detail="Error: internal server error")


@router.get(
    "/pemesanan",
    response_model=schemas.PemesananStatusListResponse
)
async def get_pemesanan_status(
    start_date: Optional[str] = Query(None, description="Filter tanggal mulai (YYYY-MM-DD)"),
    end_date: Optional[str] = Query(None, description="Filter tanggal selesai (YYYY-MM-DD)"),
    status_pemesanan: Optional[str] = Query(None, description="Filter status pemesanan (PO/SO/SA/PA)"),
    db3: Session = Depends(get_db3),
    dependencies=Depends(get_current_user)
):
    username = dependencies.username
    try:
        result = CheckinService.get_pemesanan_status(
            db3=db3,
            kode_sales=username,
            start_date=start_date,
            end_date=end_date,
            status_filter=status_pemesanan
        )
        return schemas.PemesananStatusListResponse(
            data=result,
            meta={
                "status_code": 200,
                "success": True,
                "message": "Successfully retrieved customer order statuses"
            }
        )
    except Exception as e:
        logger.error(f"error : {e}", extra={"username": username}, exc_info=True)
        raise HTTPException(status_code=500, detail="Error: internal server error")


@router.put(
    "/status/{no_activity}",
    response_model=schemas.CheckinFtthResponse
)
async def update_checkin_status(
    no_activity: str,
    payload: schemas.CheckinFtthUpdateStatus,
    db3: Session = Depends(get_db3),
    dependencies=Depends(get_current_user)
):
    username = dependencies.username
    try:
        result = CheckinService.update_checkin_status(
            db3=db3,
            no_activity=no_activity,
            kode_sales=username,
            status_pemesanan=payload.status_pemesanan,
            keterangan=payload.keterangan
        )
        return schemas.CheckinFtthResponse(
            data=result,
            meta={
                "status_code": 200,
                "success": True,
                "message": "Successfully updated checkin status and notes"
            }
        )
    except ValueError as ve:
        logger.error(f"error : {ve}", extra={"username": username})
        raise HTTPException(status_code=400, detail=str(ve))
    except Exception as e:
        logger.error(f"error : {e}", extra={"username": username}, exc_info=True)
        raise HTTPException(status_code=500, detail="Error: internal server error")


@router.post(
    "/verify-fat",
    response_model=schemas.CheckFatVerificationResponse,
    status_code=200
)
@limiter.limit("5/minute")
async def verify_fat(
    request: Request,
    foto_fat: UploadFile = File(...),
    form_data: schemas.CheckFatVerificationRequest = Depends(schemas.CheckFatVerificationRequest.as_form),
    db2: Session = Depends(get_db2),
    dependencies=Depends(get_current_user)
):
    username = dependencies.username
    start_time = time.time()
    try:
        # Baca byte data foto
        image_data = await foto_fat.read()
        
        # Proses validasi
        result = await CheckinService.verify_fat_logic(
            db2=db2,
            image_data=image_data,
            lat_sales=form_data.latitude_sales,
            lon_sales=form_data.longitude_sales
        )
        
        # Hitung total waktu proses dalam milidetik
        total_time_ms = round((time.time() - start_time) * 1000, 2)
        result["total_time_ms"] = total_time_ms
        
        return schemas.CheckFatVerificationResponse(
            data=result,
            meta={
                "status_code": 200,
                "success": True,
                "message": "Proses pengecekan FAT selesai dijalankan."
            }
        )
    except Exception as e:
        logger.error(f"error verify fat: {e}", extra={"username": username}, exc_info=True)
        raise HTTPException(status_code=500, detail="Error: internal server error")

@router.post(
    "/performance-test",
    response_model=schemas.PerformanceTestResponse,
    status_code=200
)
@limiter.limit("35/minute")
async def verify_fat_performance(
    request: Request,
    foto_fat: UploadFile = File(...),
    form_data: schemas.CheckFatVerificationRequest = Depends(schemas.CheckFatVerificationRequest.as_form),
    db2: Session = Depends(get_db2),
    dependencies=Depends(get_current_user)
):
    username = dependencies.username
    start_time_total = time.perf_counter()
    try:
        # 1. Waktu baca file (upload part backend)
        start_read = time.perf_counter()
        image_data = await foto_fat.read()
        file_read_time_ms = (time.perf_counter() - start_read) * 1000
        
        # 2. Proses validasi dengan timer yolo, ocr, spatial
        result = await CheckinService.verify_fat_performance_logic(
            db2=db2,
            image_data=image_data,
            lat_sales=form_data.latitude_sales,
            lon_sales=form_data.longitude_sales
        )
        
        # Hitung total waktu proses backend
        backend_total_time_ms = (time.perf_counter() - start_time_total) * 1000
        
        response_data = {
            "backend_total_time_ms": round(backend_total_time_ms, 2),
            "file_read_time_ms": round(file_read_time_ms, 2),
            "yolo_time_ms": result.get("yolo_time_ms"),
            "ocr_time_ms": result.get("ocr_time_ms"),
            "spatial_validation_time_ms": result.get("spatial_validation_time_ms"),
            "verified": result.get("verified"),
            "verification_method": result.get("verification_method"),
            "message": result.get("message")
        }
        
        return schemas.PerformanceTestResponse(
            data=response_data,
            meta={
                "status_code": 200,
                "success": True,
                "message": "Performance test berhasil dieksekusi."
            }
        )
    except Exception as e:
        logger.error(f"error performance test: {e}", extra={"username": username}, exc_info=True)
        raise HTTPException(status_code=500, detail="Error: internal server error")

@router.put(
    "/update-fat/new/{no_activity}",
    response_model=schemas.SubmitNewFatResponse,
    status_code=200
)
async def update_fat_new(
    no_activity: str,
    form_data: schemas.UpdateFatNewRequest = Depends(schemas.UpdateFatNewRequest.as_form),
    db3: Session = Depends(get_db3),
    dependencies=Depends(get_current_user)
):
    username = dependencies.username
    try:
        data = form_data.model_dump()
        result = CheckinService.update_fat_new(
            db3=db3,
            no_activity=no_activity,
            kode_sales=username,
            payload_data=data
        )
        
        return schemas.SubmitNewFatResponse(
            data=result,
            meta={
                "status_code": 200,
                "success": True,
                "message": "Successfully updated checkin to use newly created FAT"
            }
        )
    except ValueError as ve:
        logger.error(f"error : {ve}", extra={"username": username})
        raise HTTPException(status_code=400, detail=str(ve))
    except Exception as e:
        logger.error(f"error : {e}", extra={"username": username}, exc_info=True)
        raise HTTPException(status_code=500, detail="Error: internal server error")

@router.put(
    "/update-fat/join/{no_activity}",
    response_model=schemas.SubmitNewFatResponse,
    status_code=200
)
async def update_fat_join(
    no_activity: str,
    form_data: schemas.UpdateFatJoinRequest = Depends(schemas.UpdateFatJoinRequest.as_form),
    db3: Session = Depends(get_db3),
    dependencies=Depends(get_current_user)
):
    username = dependencies.username
    try:
        result = CheckinService.update_fat_join(
            db3=db3,
            no_activity=no_activity,
            kode_sales=username,
            fat_code=form_data.fat_code
        )
        
        return schemas.SubmitNewFatResponse(
            data=result,
            meta={
                "status_code": 200,
                "success": True,
                "message": "Successfully updated checkin to join existing FAT"
            }
        )
    except ValueError as ve:
        logger.error(f"error : {ve}", extra={"username": username})
        raise HTTPException(status_code=400, detail=str(ve))
    except Exception as e:
        logger.error(f"error : {e}", extra={"username": username}, exc_info=True)
        raise HTTPException(status_code=500, detail="Error: internal server error")
