import csv
import io
from typing import Optional
from uuid import UUID

from fastapi import APIRouter, Depends, File, Query, UploadFile, status
from fastapi.responses import StreamingResponse
from sqlalchemy import text
from sqlalchemy.orm import Session

from src.apps.base.schemas.response_model import ResponseModel
from src.apps.export_data.schemas.export_data import ExportDataFilterSchema
from src.apps.export_data.services.download_file import (
    get_all_latest_download_files,
    get_all_latest_uploaded_files,
)
from src.apps.export_data.services.export_data import (
    download_file,
    download_file_by_name,
    download_history_file,
    download_matched_file,
    get_export_file,
    process_uploaded_file_date,
    save_uploaded_file,
)
from src.core.dependencies import get_db
from src.core.exceptions import APIException
from src.utils import constants
from src.utils.constants import MAX_PER_PAGE

router = APIRouter(prefix="", tags=["Export Data"])


@router.get("/generate", response_model=ResponseModel, summary="Download export file")
async def download_export_file(
    db: Session = Depends(get_db),
    payload: ExportDataFilterSchema = Depends(),
):
    """Download export file based on the provided filter criteria.
    Args:
        db (Session): Database session dependency.
        payload (ExportDataFilterSchema): Filter criteria for the export file.
    Returns:
        ResponseModel: Contains the export file data or an error message.
    """
    data = await get_export_file(db=db, payload=payload)
    return ResponseModel(
        data=data, success=True, message="Export file generated successfully.", status_code=status.HTTP_200_OK
    )


@router.get("/latest-files", response_model=ResponseModel, summary="Get latest export files")
async def get_latest_export_files(
    db: Session = Depends(get_db),
):
    """
    Get the latest export files based on the specified type and limit.
    Args:
        db (Session): Database session dependency.
    Returns:
        ResponseModel: Contains the latest export files or an error message.
    This endpoint retrieves the latest export files from the database.
    It uses the `get_export_latest_files` service to fetch the files.
    The response includes a success status, message, and the data containing the latest files.
    If no files are found, it returns an empty list.
    If an error occurs, it returns a failure response with an appropriate message.
    """
    data = await get_all_latest_download_files(db=db)
    return ResponseModel(
        data=data, success=True, message="Latest export files retrieved successfully.", status_code=status.HTTP_200_OK
    )


@router.get("/download", summary="Download a specific export file by type")
async def download_specific_export_file(
    db: Session = Depends(get_db),
    payload: ExportDataFilterSchema = Depends(),
):
    """
    Download a specific export file based on the provided type.
    Args:
        db (Session): Database session dependency.
        payload (ExportDataFilterSchema): Filter criteria for the export file, including type.
    Returns:
        ResponseModel: Contains the export file data or an error message.
    """
    return await download_file(db=db, payload=payload)


@router.get("/download-by-name", summary="Download a specific export file by name")
async def download_export_file_by_name(
    db: Session = Depends(get_db),
    file_name: str = Query(..., description="Name of the file to download"),
):
    """
    Download a specific export file based on the provided file name.
    Args:
        db (Session): Database session dependency.
        file_name (str): Name of the file to download.
    Returns:
        ResponseModel: Contains the export file data or an error message.
    """
    return await download_file_by_name(db=db, file_name=file_name)


@router.post("/upload-csv/")
async def upload_csv(
    db: Session = Depends(get_db),
    file: UploadFile = File(...),
    payload: ExportDataFilterSchema = Depends(),
):
    """
    Upload a CSV file and save it locally.
    """
    # Validate file type
    if not file.filename.endswith(".txt"):
        raise APIException(
            module="upload_file",
            error="Only TXT files are allowed",
            status_code=status.HTTP_400_BAD_REQUEST,
            message="Only TXT files are allowed",
        )

    data = await save_uploaded_file(db=db, file=file, payload=payload)
    return ResponseModel(
        data=data, success=True, message="Latest export files upoaded successfully.", status_code=status.HTTP_200_OK
    )


@router.get("/latest-upliaded-files", response_model=ResponseModel, summary="Get latest uploaded files")
async def get_latest_export_files(
    db: Session = Depends(get_db),
):
    """
    Get the latest export files based on the specified type and limit.
    Args:
        db (Session): Database session dependency.
    Returns:
        ResponseModel: Contains the latest export files or an error message.
    This endpoint retrieves the latest export files from the database.
    It uses the `get_export_latest_files` service to fetch the files.
    The response includes a success status, message, and the data containing the latest files.
    If no files are found, it returns an empty list.
    If an error occurs, it returns a failure response with an appropriate message.
    """
    data = await get_all_latest_uploaded_files(db=db)
    return ResponseModel(
        data=data, success=True, message="Latest uploaded files retrieved successfully.", status_code=status.HTTP_200_OK
    )


@router.get("/process-uploaded-file/{type}", response_model=ResponseModel, summary="Preview uploaded CSV file")
async def process_uploaded_file(
    type: str,
    db: Session = Depends(get_db),
):
    """
    Process the uploaded CSV file based on the provided type.
    Args:
        db (Session): Database session dependency.
        type (str): Type of the uploaded file to process.
    Returns:
        ResponseModel: Contains the processed file data or an error message.
    """
    data = await process_uploaded_file_date(db=db, type=type)
    return ResponseModel(
        data=data, success=True, message="Uploaded file processed successfully.", status_code=status.HTTP_200_OK
    )


@router.get("/get-matched-file", summary="Test endpoint to check API status")
async def get_matched_file(
    db: Session = Depends(get_db),
    code: str = Query(..., description="ID of the file to retrieve matched data for"),
    date: str = Query(..., description="Date of the file to retrieve matched data for"),
):
    """
    Retrieve matched data for a specific file by its ID.
    Args:
        db (Session): Database session dependency.
        file_id (UUID, optional): ID of the file to retrieve matched data for.
    Returns:
        ResponseModel: Contains the matched data or an error message.
    """
    return await download_matched_file(db=db, code=code, date=date)


@router.get("/get-history-file", summary="Test endpoint to check API status")
async def get_history_file(
    db: Session = Depends(get_db),
    file_name: str = Query(..., description="ID of the file to retrieve matched data for"),
):
    """
    Retrieve matched data for a specific file by its ID.
    Args:
        db (Session): Database session dependency.
        file_id (UUID, optional): ID of the file to retrieve matched data for.
    Returns:
        ResponseModel: Contains the matched data or an error message.
    """
    return await download_history_file(db=db, file_name=file_name)
