from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.middleware.cors import CORSMiddleware
from fastapi.middleware.trustedhost import TrustedHostMiddleware
from fastapi.middleware.httpsredirect import HTTPSRedirectMiddleware
from fastapi.security import OAuth2PasswordRequestForm
from sqlalchemy.orm import Session
from typing import Optional

from app.utils import create_access_token
from . import schemas, crud
from .database import SessionLocal, engine, Base

Base.metadata.create_all(bind=engine)

app = FastAPI()

app.add_middleware(
    TrustedHostMiddleware, allowed_hosts=["site-api.muszyn.dev", "*.muszyn.dev"]
)
app.add_middleware(
    CORSMiddleware,
    allow_origins=[
        "http://localhost:3000",
        "http://localhost:8000",
        "http://192.168.125.129:3000",
        "https://192.168.125.129:3000",
        "http://192.168.125.129:8000",
        "https://192.168.125.129:8000",
        "https://site.muszyn.dev",
    ],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)


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


@app.get("/check-health")
def health_check():
    return {"Health": "Super Healthy!"}


@app.post("/blogs/", response_model=schemas.Blog)
def create_blog(
    blog: schemas.BlogCreate,
    db: Session = Depends(get_db),
):
    return crud.create_blog(db, blog)


@app.get("/blogs/", response_model=list[schemas.Blog])
def read_blogs(
    skip: int = 0,
    limit: int = 10,
    author_id: Optional[int] = None,
    db: Session = Depends(get_db),
):
    return crud.get_blogs(
        db,
        skip=skip,
        limit=limit,
        author_id=author_id,
    )


@app.get("/blogs/{blog_id}", response_model=schemas.Blog)
def read_blog(
    blog_id: int,
    db: Session = Depends(get_db),
):
    db_blog = crud.get_blog(db, blog_id)
    if not db_blog:
        raise HTTPException(status_code=404, detail="Blog not found")
    return db_blog


@app.put("/blogs/{blog_id}", response_model=schemas.Blog)
def update_blog(
    blog_id: int,
    blog_in: schemas.BlogUpdate,
    db: Session = Depends(get_db),
):
    updated = crud.update_blog(db, blog_id, blog_in)
    if not updated:
        raise HTTPException(status_code=404, detail="Blog not found")
    return updated


@app.delete("/blogs/{blog_id}", response_model=schemas.Blog)
def delete_blog(
    blog_id: int,
    db: Session = Depends(get_db),
):
    deleted = crud.delete_blog(db, blog_id)
    if not deleted:
        raise HTTPException(status_code=404, detail="Blog not found")
    return deleted


# Users
@app.post("/login", response_model=schemas.Token)
def user_login(
    form_data: OAuth2PasswordRequestForm = Depends(), db: Session = Depends(get_db)
):
    user = crud.authenticate_user(db, form_data.username, form_data.password)
    if not user:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Incorrect username or password",
            headers={"WWW-Authenticate": "Bearer"},
        )
    access_token = create_access_token(data={"sub": user.username})
    return {"access_token": access_token, "token_type": "bearer", "user_id": user.id}


@app.post("/register", response_model=schemas.UserOut)
def register_user(user: schemas.UserCreate, db: Session = Depends(get_db)):
    if crud.get_user_by_username(db, user.username):
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Username already registered",
        )
    if crud.get_user_by_email(db, user.email):
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Account with that email already registered",
        )
    # Default Cases
    return crud.create_user(db, user)
