from fastapi import FastAPI, HTTPException, Depends
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from typing import Optional
import pandas as pd
from io import BytesIO
from fastapi.responses import StreamingResponse
import logging
from datetime import datetime
from dateutil.relativedelta import relativedelta

from scrapers import AttendanceScraper, JourneybookScraper
from calculators.kilometer_calculator import KilometerCalculator
from fillers import JourneybookFiller

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

app = FastAPI(title="Kniha Jízd API", version="1.0.0")

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)


class ScrapeRequest(BaseModel):
    username: str
    password: str
    month: str
    vehicle_registration: str = "4SH1148"


class CalculateRequest(BaseModel):
    username: str
    password: str
    start_date: str  # Format: YYYY-MM-DD
    end_date: str    # Format: YYYY-MM-DD
    start_km: int
    end_km: int
    vehicle_registration: str = "4SH1148"
    variance: float = 0.1


class FillRequest(CalculateRequest):
    dry_run: bool = True


@app.get("/health")
async def health_check():
    return {"status": "healthy"}


@app.post("/api/scrape/attendance")
async def scrape_attendance(request: ScrapeRequest):
    """Scrape attendance data for a month"""
    try:
        scraper = AttendanceScraper(request.username, request.password)
        attendance_dates = scraper.scrape_month(request.month)
        return {
            "month": request.month,
            "sick_vacation_days": attendance_dates,
            "count": len(attendance_dates)
        }
    except Exception as e:
        logger.error(f"Attendance scraping failed: {e}")
        raise HTTPException(status_code=500, detail=str(e))


@app.post("/api/scrape/journeybook")
async def scrape_journeybook(request: ScrapeRequest):
    """Scrape journeybook data for a month"""
    try:
        scraper = JourneybookScraper(request.username, request.password, request.vehicle_registration)
        df = scraper.scrape_month(request.month)

        return {
            "month": request.month,
            "entries": df.to_dict(orient='records'),
            "count": len(df)
        }
    except Exception as e:
        logger.error(f"Journeybook scraping failed: {e}")
        raise HTTPException(status_code=500, detail=str(e))


@app.post("/api/calculate")
async def calculate_kilometers(request: CalculateRequest):
    """Scrape data, filter sick days, and recalculate kilometers"""
    try:
        logger.info(f"Calculate request: start_date={request.start_date}, end_date={request.end_date}")
        attendance_scraper = AttendanceScraper(request.username, request.password)
        journeybook_scraper = JourneybookScraper(request.username, request.password, request.vehicle_registration)

        # Get all months in the date range
        start = datetime.strptime(request.start_date, "%Y-%m-%d")
        end = datetime.strptime(request.end_date, "%Y-%m-%d")
        logger.info(f"Parsed dates: start={start}, end={end}")

        # Collect data from all months
        all_attendance_dates = []
        all_dfs = []

        current = start
        while current <= end:
            month_str = current.strftime("%Y-%m")
            logger.info(f"Scraping attendance for {month_str}")
            attendance_dates = attendance_scraper.scrape_month(month_str)
            all_attendance_dates.extend(attendance_dates)

            logger.info(f"Scraping journeybook for {month_str}")
            df_month = journeybook_scraper.scrape_month(month_str)
            all_dfs.append(df_month)

            current = current + relativedelta(months=1)

        # Combine all months
        df = pd.concat(all_dfs, ignore_index=True) if all_dfs else pd.DataFrame()

        # Filter by actual date range, but preserve refueling rows (empty Datum)
        if not df.empty:
            date_parsed = pd.to_datetime(df["Datum"], format="%d.%m.%Y", errors='coerce')
            is_refuel = df["Datum"].isna() | (df["Datum"] == "")
            is_in_range = (date_parsed >= start) & (date_parsed <= end)
            df = df[is_in_range | is_refuel]

        logger.info(f"Filtering out {len(all_attendance_dates)} sick/vacation days")
        # Only filter journey rows, not refueling rows
        is_refuel = df["Datum"].isna() | (df["Datum"] == "")
        df = df[~df["Datum"].isin(all_attendance_dates) | is_refuel]

        logger.info("Recalculating kilometers")
        df = KilometerCalculator.recalculate(df, request.start_km, request.end_km, request.variance)

        return {
            "month": f"{request.start_date} - {request.end_date}",
            "start_km": request.start_km,
            "end_km": request.end_km,
            "filtered_days": len(all_attendance_dates),
            "entries": df.to_dict(orient='records'),
            "total_entries": len(df)
        }
    except Exception as e:
        import traceback
        logger.error(f"Calculate failed: {e}")
        logger.error(traceback.format_exc())
        raise HTTPException(status_code=500, detail=str(e))


@app.post("/api/export/excel")
async def export_to_excel(request: CalculateRequest):
    """Generate and download Excel file"""
    try:
        attendance_scraper = AttendanceScraper(request.username, request.password)
        journeybook_scraper = JourneybookScraper(request.username, request.password, request.vehicle_registration)

        # Get all months in the date range
        start = datetime.strptime(request.start_date, "%Y-%m-%d")
        end = datetime.strptime(request.end_date, "%Y-%m-%d")

        # Collect data from all months
        all_attendance_dates = []
        all_dfs = []

        current = start
        while current <= end:
            month_str = current.strftime("%Y-%m")
            attendance_dates = attendance_scraper.scrape_month(month_str)
            all_attendance_dates.extend(attendance_dates)
            df_month = journeybook_scraper.scrape_month(month_str)
            all_dfs.append(df_month)
            current = current + relativedelta(months=1)

        # Combine all months
        df = pd.concat(all_dfs, ignore_index=True) if all_dfs else pd.DataFrame()

        # Filter by actual date range, but preserve refueling rows (empty Datum)
        if not df.empty:
            date_parsed = pd.to_datetime(df["Datum"], format="%d.%m.%Y", errors='coerce')
            is_refuel = df["Datum"].isna() | (df["Datum"] == "")
            is_in_range = (date_parsed >= start) & (date_parsed <= end)
            df = df[is_in_range | is_refuel]

        # Only filter journey rows, not refueling rows
        is_refuel = df["Datum"].isna() | (df["Datum"] == "")
        df = df[~df["Datum"].isin(all_attendance_dates) | is_refuel]
        df = KilometerCalculator.recalculate(df, request.start_km, request.end_km, request.variance)

        output = BytesIO()
        df.to_excel(output, index=False, engine='openpyxl')
        output.seek(0)

        filename = f"journeybook_{request.start_date}_{request.end_date}.xlsx"
        return StreamingResponse(
            output,
            media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
            headers={"Content-Disposition": f"attachment; filename={filename}"}
        )
    except Exception as e:
        logger.error(f"Export failed: {e}")
        raise HTTPException(status_code=500, detail=str(e))


@app.post("/api/fill/journeybook")
async def fill_journeybook(request: FillRequest):
    """Fill calculated data back to kj.colsys.cz (restricted to January 2025)"""
    try:
        logger.info(f"Fill request received with dry_run={request.dry_run}")

        # Only allow January 2025 for testing
        if request.start_date != "2025-01-01" or request.end_date < "2025-01-31":
            raise HTTPException(status_code=400, detail="Only January 2025 is allowed for testing")

        attendance_scraper = AttendanceScraper(request.username, request.password)
        journeybook_scraper = JourneybookScraper(request.username, request.password, request.vehicle_registration)

        # Get January data
        month_str = "2025-01"
        attendance_dates = attendance_scraper.scrape_month(month_str)
        df = journeybook_scraper.scrape_month(month_str)

        # Filter sick/vacation days
        df = df[~df["Datum"].isin(attendance_dates)]

        # Recalculate kilometers
        df = KilometerCalculator.recalculate(df, request.start_km, request.end_km, request.variance)

        # Fill data back (supports dry_run mode)
        filler = JourneybookFiller(request.username, request.password, request.vehicle_registration)
        result = filler.fill_month(df, month_str, dry_run=request.dry_run)

        return result
    except Exception as e:
        import traceback
        logger.error(f"Fill failed: {e}")
        logger.error(traceback.format_exc())
        raise HTTPException(status_code=500, detail=str(e))


if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)
