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

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

Base.metadata.create_all(bind=engine)


class MosquitoReportBase(BaseModel):
    location: str
    date: datetime
    contamination_rate: float
    observations: Optional[str] = None
    disease: Optional[str] = None

    class Config:
        orm_mode = True


class MosquitoReportCreate(MosquitoReportBase):
    pass


class MosquitoReport(MosquitoReportBase):
    id: int

    class Config:
        orm_mode = True


class SymptomeBase(BaseModel):
    nom: str
    maladie: Maladie

    class Config:
        orm_mode = True


class MaladieBase(BaseModel):
    nom: str

    class Config:
        orm_mode = True

class MaladieCreate(MaladieBase):
    pass

class Maladie(MaladieBase):
    id: int
    symptomes: List[Symptome] = []
    traitements: List[Traitement] = []

    class Config:
        orm_mode = True

class TraitementBase(BaseModel):
    description: str
    maladie: Maladie

    class Config:
        orm_mode = True


class TraitementCreate(TraitementBase):
    pass


class Traitement(TraitementBase):
    id: int

    class Config:
        orm_mode = True


class ContaminationRateBase(BaseModel):
    total_contaminated: int
    total_tested: int
    maladie: Maladie

    class Config:
        orm_mode = True


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


app = FastAPI()


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


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


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


@app.post("/maladies/", response_model=Maladie)
def create_maladie(maladie: MaladieCreate, 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("/maladies/", response_model=List[Maladie])
def read_maladies(skip: int = 0, limit: int = 10, db: Session = Depends(get_db)):
    maladies = db.query(Maladie).offset(skip).limit(limit).all()
    return maladies


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


@app.post("/traitements/", response_model=Traitement)
def create_traitement(traitement: TraitementCreate, 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("/traitements/", response_model=List[Traitement])
def read_traitements(skip: int = 0, limit: int = 10, db: Session = Depends(get_db)):
    traitements = db.query(Traitement).offset(skip).limit(limit).all()
    return traitements


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


class SymptomeCreate:
    nom: str
    maladie_id: int

class Symptome(BaseModel):
    id: int
    nom: str
    maladie_id: int

    class Config:
        orm_mode = True



@app.post("/symptomes/", response_model=Symptome)
def create_symptome(symptome: SymptomeCreate, db: Session = Depends(get_db)):
    db_symptome = Symptome(**symptome.dict())
    db.add(db_symptome)
    db.commit()
    db.refresh(db_symptome)
    return db_symptome


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


@app.get("/symptomes/{symptome_id}", response_model=Symptome)
def read_symptome(symptome_id: int, db: Session = Depends(get_db)):
    symptome = db.query(Symptome).filter(Symptome.id == symptome_id).first()
    if symptome is None:
        raise HTTPException(status_code=404, detail="Symptome not found")
    return symptome


@app.post("/contamination_rates/", response_model=Contamination)
def create_contamination_rate(contamination_rate: ContaminationRateBase, db: Session = Depends(get_db)):
    db_contamination_rate = Contamination(**contamination_rate.dict())
    db.add(db_contamination_rate)
    db.commit()
    db.refresh(db_contamination_rate)
    return db_contamination_rate


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


@app.get("/contamination_rates/{contamination_rate_id}", response_model=Contamination)
def read_contamination_rate(contamination_rate_id: int, db: Session = Depends(get_db)):
    contamination_rate = db.query(Contamination).filter(Contamination.id == contamination_rate_id).first()
    if contamination_rate is None:
        raise HTTPException(status_code=404, detail="Contamination rate not found")
    return contamination_rate


@app.get("/maladies/{maladie_id}/contamination_rates", response_model=List[Contamination])
def read_contamination_rates_by_maladie(maladie_id: int, db: Session = Depends(get_db)):
    contamination_rates = db.query(Contamination).filter(Contamination.maladie_id == maladie_id).all()
    return contamination_rates





@app.get("/maladies/{maladie_id}/contamination_rates/average", response_model=float)
def read_average_contamination_rate_by_maladie(maladie_id: int, db: Session = Depends(get_db)):
    average_contamination_rate = db.query(func.avg(Contamination.total_contaminated / Contamination.total_tested)).filter(Contamination.maladie_id == maladie_id).scalar()
    return average_contamination_rate


@app.get("/maladies/{maladie_id}/contamination_rates/total", response_model=int)
def read_total_contamination_rate_by_maladie(maladie_id: int, db: Session = Depends(get_db)):
    total_contamination_rate = db.query(func.sum(Contamination.total_contaminated)).filter(Contamination.maladie_id == maladie_id).scalar()
    return total_contamination_rate