import os
import jwt
import bcrypt
import psycopg2
from datetime import datetime, timedelta
from fastapi import Request, HTTPException
from dotenv import load_dotenv

load_dotenv(override=True)

JWT_SECRET = os.getenv("JWT_SECRET", "nihf38rn28rhf8nr3")
JWT_ALGORITHM = os.getenv("JWT_ALGORITHM", "HS256")
JWT_EXPIRATION_MINUTES = int(os.getenv("JWT_EXPIRATION_MINUTES", "1440"))


# ─────────────────────────────────────────
# DB CONNECTION
# ─────────────────────────────────────────

def get_connection():
    return psycopg2.connect(
        host=os.getenv("DB_HOST", "localhost"),
        port=os.getenv("DB_PORT", "5432"),
        database=os.getenv("DB_NAME", "fyndo"),
        user=os.getenv("DB_USER", "postgres"),
        password=os.getenv("DB_PASSWORD", "")
    )


# ─────────────────────────────────────────
# PASSWORD
# ─────────────────────────────────────────

def hash_password(password: str) -> str:
    return bcrypt.hashpw(password.encode(), bcrypt.gensalt()).decode()


def verify_password(password: str, hashed: str) -> bool:
    return bcrypt.checkpw(password.encode(), hashed.encode())


# ─────────────────────────────────────────
# JWT
# ─────────────────────────────────────────

def create_token(user_id: int, email: str, name: str) -> str:
    payload = {
        "id": user_id,
        "email": email,
        "name": name,
        "exp": datetime.utcnow() + timedelta(minutes=JWT_EXPIRATION_MINUTES),
        "iat": datetime.utcnow()
    }
    return jwt.encode(payload, JWT_SECRET, algorithm=JWT_ALGORITHM)


# ─────────────────────────────────────────
# GET USER FROM TOKEN — same pattern as Fyndo RFP
# ─────────────────────────────────────────

def get_user_from_token(request: Request) -> str:
    authorization = request.headers.get("Authorization")
    print("Auth header:", authorization)

    if not authorization or not authorization.startswith("Bearer "):
        raise HTTPException(status_code=401, detail="Missing or invalid Authorization header")

    token = authorization.split(" ")[1]
    print("Extracted token:", token)

    try:
        payload = jwt.decode(token, JWT_SECRET, algorithms=[JWT_ALGORITHM])
    except jwt.ExpiredSignatureError:
        raise HTTPException(status_code=401, detail="Token expired. Please login again.")
    except Exception as e:
        print("Decode error:", str(e))
        raise HTTPException(status_code=401, detail="Invalid token")

    user_id = payload.get("id")
    print("Decoded user_id:", user_id)

    if not user_id:
        raise HTTPException(status_code=400, detail="Invalid token payload")

    return user_id


# ─────────────────────────────────────────
# DB USER FUNCTIONS
# ─────────────────────────────────────────

def get_user_by_email(email: str):
    conn = get_connection()
    cur = conn.cursor()
    cur.execute(
        "SELECT id, name, email, password_hash, created_at FROM users WHERE email = %s",
        (email,)
    )
    row = cur.fetchone()
    cur.close()
    conn.close()
    if not row:
        return None
    return {
        "id": row[0],
        "name": row[1],
        "email": row[2],
        "password_hash": row[3],
        "created_at": str(row[4])
    }


def register_user(name: str, email: str, password: str) -> dict:
    conn = get_connection()
    cur = conn.cursor()
    password_hash = hash_password(password)
    try:
        cur.execute(
            """
            INSERT INTO users (name, email, password_hash)
            VALUES (%s, %s, %s)
            RETURNING id, name, email, created_at
            """,
            (name, email, password_hash)
        )
        row = cur.fetchone()
        conn.commit()
        return {
            "id": row[0],
            "name": row[1],
            "email": row[2],
            "created_at": str(row[3])
        }
    except psycopg2.errors.UniqueViolation:
        conn.rollback()
        raise HTTPException(status_code=400, detail="Email already registered.")
    finally:
        cur.close()
        conn.close()