from fastapi import FastAPI, HTTPException, UploadFile, File, Form, Depends
from fastapi.responses import FileResponse, JSONResponse
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from pydantic import BaseModel
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import sessionmaker
from sqlalchemy import text
from datetime import datetime, timedelta, date
from jose import JWTError, jwt
import bcrypt, os, uuid, traceback
from dotenv import load_dotenv

load_dotenv()

SECRET_KEY = "SZUPER_TITKOS_KULCS_2026"
ALGORITHM = "HS256"
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="api/auth/login")

DATABASE_URL = os.getenv("DATABASE_URL", "").replace("postgresql://", "postgresql+asyncpg://")
engine = create_async_engine(DATABASE_URL, pool_pre_ping=True)
AsyncSessionLocal = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)

app = FastAPI()

# --- AUTH ---
def get_password_hash(password: str):
    pwd_bytes = password.encode('utf-8')
    return bcrypt.hashpw(pwd_bytes[:72], bcrypt.gensalt()).decode('utf-8')

def verify_password(plain, hashed):
    return bcrypt.checkpw(plain.encode('utf-8')[:72], hashed.encode('utf-8'))

async def get_current_user(token: str = Depends(oauth2_scheme)):
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        return int(payload.get("sub"))
    except: raise HTTPException(status_code=401)

# --- API ---
@app.post("/api/auth/register")
async def register(email: str = Form(...), password: str = Form(...)):
    async with AsyncSessionLocal() as session:
        async with session.begin():
            h = get_password_hash(password)
            await session.execute(text("INSERT INTO data.users (email, password_hash) VALUES (:e, :p)"), {"e": email, "p": h})
            return {"status": "success"}

@app.post("/api/auth/login")
async def login(f: OAuth2PasswordRequestForm = Depends()):
    async with AsyncSessionLocal() as session:
        res = await session.execute(text("SELECT id, password_hash FROM data.users WHERE email = :e"), {"e": f.username})
        u = res.fetchone()
        if not u or not verify_password(f.password, u.password_hash): raise HTTPException(status_code=401)
        token = jwt.encode({"sub": str(u.id), "exp": datetime.utcnow() + timedelta(days=1)}, SECRET_KEY, algorithm=ALGORITHM)
        return {"access_token": token, "token_type": "bearer"}

@app.get("/api/my_vehicles")
async def my_vehicles(uid: int = Depends(get_current_user)):
    async with AsyncSessionLocal() as session:
        q = text("SELECT v.id as vehicle_id, v.current_plate as plate, m.name as brand, mo.model_name as model, v.status FROM data.vehicle_history vh JOIN data.vehicles v ON vh.vehicle_id = v.id JOIN ref.vehicle_models mo ON v.model_id = mo.id JOIN ref.vehicle_makes m ON mo.make_id = m.id WHERE vh.user_id = :uid AND vh.end_date IS NULL")
        res = await session.execute(q, {"uid": uid})
        return [dict(r._mapping) for r in res.fetchall()]

@app.get("/api/vehicles")
async def all_models():
    async with AsyncSessionLocal() as session:
        q = text("SELECT vm.id, m.name as brand, vm.model_name as model FROM ref.vehicle_models vm JOIN ref.vehicle_makes m ON vm.make_id = m.id ORDER BY brand, model")
        res = await session.execute(q)
        return [dict(r._mapping) for r in res.fetchall()]

class VehicleReg(BaseModel): model_id: int; vin: str; plate: str; mileage: int; purchase_date: date

@app.post("/api/register")
async def register_vehicle(d: VehicleReg, uid: int = Depends(get_current_user)):
    async with AsyncSessionLocal() as session:
        async with session.begin():
            # Új jármű vagy meglévő
            res = await session.execute(text("INSERT INTO data.vehicles (model_id, vin, current_plate) VALUES (:mid, :vin, :plt) RETURNING id"), {"mid": d.model_id, "vin": d.vin, "plt": d.plate})
            vid = res.scalar()
            await session.execute(text("INSERT INTO data.vehicle_history (vehicle_id, user_id, role, start_date, start_mileage) VALUES (:vid, :uid, 'OWNER', :sd, :sm)"), {"vid": vid, "uid": uid, "sd": d.purchase_date, "sm": d.mileage})
            return {"status": "success"}

@app.get("/api/vehicle/{vid}")
async def get_details(vid: int, uid: int = Depends(get_current_user)):
    async with AsyncSessionLocal() as session:
        q = text("SELECT v.id, v.current_plate as plate, m.name as brand, mo.model_name as model, vh.start_mileage as mileage, v.status, u.default_currency as currency FROM data.vehicle_history vh JOIN data.vehicles v ON vh.vehicle_id = v.id JOIN ref.vehicle_models mo ON v.model_id = mo.id JOIN ref.vehicle_makes m ON mo.make_id = m.id JOIN data.users u ON vh.user_id = u.id WHERE v.id = :vid AND vh.user_id = :uid")
        res = await session.execute(q, {"vid": vid, "uid": uid})
        car = res.fetchone()
        if not car: raise HTTPException(status_code=404)
        
        # Idei költség
        c_q = text("SELECT SUM(amount) FROM data.costs WHERE vehicle_id = :vid AND EXTRACT(YEAR FROM date) = 2026")
        cost = (await session.execute(c_q, {"vid": vid})).scalar() or 0
        
        return {**dict(car._mapping), "year_cost": cost}

@app.post("/api/add_cost")
async def add_cost(vehicle_id: int = Form(...), cost_type: str = Form(...), amount: float = Form(...), currency: str = Form(...), mileage: int = Form(...), date_str: str = Form(...), uid: int = Depends(get_current_user)):
    async with AsyncSessionLocal() as session:
        async with session.begin():
            await session.execute(text("INSERT INTO data.costs (vehicle_id, user_id, cost_type, amount, currency, date, mileage_at_cost) VALUES (:vid, :uid, :type, :amt, :curr, :date, :mil)"), 
                                {"vid": vehicle_id, "uid": uid, "type": cost_type, "amt": amount, "curr": currency, "date": date_str, "mil": mileage})
            return {"status": "success"}

@app.get("/")
async def index(): return FileResponse("/app/frontend/index.html")