Improve : from datetime import datetime

from fastapi import FastAPI, Depends, HTTPException
from pydantic import BaseModel
from typing import Optional, List

from sqlalchemy import func
from sqlalchemy.orm import Session
from database import SessionLocal, engine, Base
from models import Mosquito as MosquitoReportModel, Traitement, Maladie

Base.metadata.create_all(bind=engine)


app = FastAPI()


class MosquitoReport(BaseModel):
    id: int
    location: str
    species: str
    date: datetime
    contamination_rate: Optional[float]
    observations: str = None
    disease: str
    number_contamination: int

    class Config:
        orm_mode = True

class ContaminationRate(BaseModel):
    species: str
    total_tested: int
    total_contaminated: int
    contamination_rate: float

    class Config:
        orm_mode = True

class TraitementSchema(BaseModel):
    id: int
    description: str
    maladie_id: int

    class Config:
        orm_mode = True

class MaladieSchema(BaseModel):
    id: int
    nom: str
    traitements: List[TraitementSchema]

    class Config:
        orm_mode = True


def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

@app.get("/")
def read_root():
    return {"message": "Welcome to the Mosquito API"}


@app.post("/mosquito/", response_model=MosquitoReport)
def create_mosquito_report(mosquito: MosquitoReport, db: Session = Depends(get_db)):
    db_mosquito = MosquitoReportModel(**mosquito.dict())
    db.add(db_mosquito)
    db.commit()
    db.refresh(db_mosquito)
    return db_mosquito

@app.get("/mosquito/{mosquito_id}", response_model=MosquitoReport)
def read_mosquito_report(mosquito_id: int, db: Session = Depends(get_db)):
    db_mosquito = db.query(MosquitoReportModel).filter(MosquitoReportModel.id == mosquito_id).first()
    if db_mosquito is None:
        raise HTTPException(status_code=404, detail="Mosquito not found")
    return db_mosquito

@app.put("/mosquito/{mosquito_id}", response_model=MosquitoReport)
def update_mosquito_report(mosquito_id: int, mosquito: MosquitoReport, db: Session = Depends(get_db)):
    db_mosquito = db.query(MosquitoReportModel).filter(MosquitoReportModel.id == mosquito_id).first()
    if db_mosquito is None:
        raise HTTPException(status_code=404, detail="Mosquito not found")
    for key, value in mosquito.dict().items():
        setattr(db_mosquito, key, value)
    db.commit()
    db.refresh(db_mosquito)
    return db_mosquito

@app.delete("/mosquito/{mosquito_id}", response_model=MosquitoReport)
def delete_mosquito_report(mosquito_id: int, db: Session = Depends(get_db)):
    db_mosquito = db.query(MosquitoReportModel).filter(MosquitoReportModel.id == mosquito_id).first()
    if db_mosquito is None:
        raise HTTPException(status_code=404, detail="Mosquito not found")
    db.delete(db_mosquito)
    db.commit()
    return db_mosquito


# Number of mosquitoes
@app.get("/mosquito/count", response_model=int)
def count_number_mosquito_reports(db: Session = Depends(get_db)):
    return db.query(MosquitoReportModel).count()

@app.get("/mosquito/last", response_model=MosquitoReport)
def read_last_mosquito_report(db: Session = Depends(get_db)):
    return db.query(MosquitoReportModel).order_by(MosquitoReportModel.date.desc()).first()

@app.get("/contamination/", response_model=List[ContaminationRate])
def read_contamination_rates(skip: int = 0, limit: int = 10, db: Session = Depends(get_db)):
    return db.query(MosquitoReportModel.species, func.count(MosquitoReportModel.species).label('total_tested'),
                    func.sum(MosquitoReportModel.contamination_rate).label('total_contaminated'),
                    func.avg(MosquitoReportModel.contamination_rate).label('contamination_rate')) \
        .group_by(MosquitoReportModel.species).offset(skip).limit(limit).all()

@app.get("/contamination/{species}", response_model=ContaminationRate)
def read_contamination_rate(species: str, db: Session = Depends(get_db)):
    return db.query(MosquitoReportModel.species, func.count(MosquitoReportModel.species).label('total_tested'),
                    func.sum(MosquitoReportModel.contamination_rate).label('total_contaminated'),
                    func.avg(MosquitoReportModel.contamination_rate).label('contamination_rate')) \
        .filter(MosquitoReportModel.species == species).group_by(MosquitoReportModel.species).first()


@app.get("/mosquito/", response_model=List[MosquitoReport])
def read_mosquito_reports(skip: int = 0, limit: int = 10, db: Session = Depends(get_db)):
    return db.query(MosquitoReportModel).offset(skip).limit(limit).all()

@app.post("/traitement/", response_model=TraitementSchema)
def create_traitement(traitement: TraitementSchema, db: Session = Depends(get_db)):
    db_traitement = Traitement(**traitement.dict())
    db.add(db_traitement)
    db.commit()
    db.refresh(db_traitement)
    return db_traitement


@app.get("/traitement/{traitement_id}", response_model=TraitementSchema)
def read_traitement(traitement_id: int, db: Session = Depends(get_db)):
    db_traitement = db.query(Traitement).filter(Traitement.id == traitement_id).first()
    if db_traitement is None:
        raise HTTPException(status_code=404, detail="Traitement not found")
    return db_traitement


@app.get("/traitement/", response_model=List[TraitementSchema])
def read_traitements(skip: int = 0, limit: int = 10, db: Session = Depends(get_db)):
    return db.query(Traitement).offset(skip).limit(limit).all()


@app.post("/maladie/", response_model=MaladieSchema)
def create_maladie(maladie: MaladieSchema, db: Session = Depends(get_db)):
    db_maladie = Maladie(**maladie.dict())
    db.add(db_maladie)
    db.commit()
    db.refresh(db_maladie)
    return db_maladie


@app.get("/maladie/{maladie_id}", response_model=MaladieSchema)
def read_maladie(maladie_id: int, db: Session = Depends(get_db)):
    db_maladie = db.query(Maladie).filter(Maladie.id == maladie_id).first()
    if db_maladie is None:
        raise HTTPException(status_code=404, detail="Maladie not found")
    return db_maladie


@app.get("/maladie/", response_model=List[MaladieSchema])
def read_maladies(skip: int = 0, limit: int = 10, db: Session = Depends(get_db)):
    return db.query(Maladie).offset(skip).limit(limit).all()