import os
import time
from pathlib import Path
from fastapi import FastAPI, Request, UploadFile, File, Form
from fastapi.responses import HTMLResponse, RedirectResponse, StreamingResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates

from .db import init_db, connect
from .import_xml import import_sms_xml
from .search import register_regex, run_search, log_search

UPLOAD_DIR = Path("data/uploads")
UPLOAD_DIR.mkdir(parents=True, exist_ok=True)

app = FastAPI()
templates = Jinja2Templates(directory="app/templates")
app.mount("/static", StaticFiles(directory="app/static"), name="static")

@app.on_event("startup")
def startup():
  init_db()

@app.get("/", response_class=HTMLResponse)
def root(request: Request):
  return RedirectResponse("/dashboard")

@app.get("/upload", response_class=HTMLResponse)
def upload_page(request: Request):
  return templates.TemplateResponse("upload.html", {"request": request})

@app.post("/upload")
async def upload(file: UploadFile = File(...)):
  # Stream to disk to handle large files
  ts = int(time.time())
  dest = UPLOAD_DIR / f"{ts}_{file.filename}"
  with dest.open("wb") as f:
    while True:
      chunk = await file.read(1024 * 1024)  # 1MB chunks
      if not chunk:
        break
      f.write(chunk)

  conn = connect()
  register_regex(conn)
  import_sms_xml(conn, str(dest))
  conn.close()

  return RedirectResponse("/dashboard", status_code=303)

@app.get("/dashboard", response_class=HTMLResponse)
def dashboard(request: Request):
  conn = connect()
  total = conn.execute("SELECT COUNT(*) AS c FROM messages").fetchone()["c"]
  recent_searches = conn.execute(
    "SELECT * FROM search_history ORDER BY created_at_ms DESC LIMIT 20"
  ).fetchall()
  bookmarks = conn.execute(
    """SELECT b.*, m.address, m.date_ms, m.body
       FROM bookmarks b JOIN messages m ON m.id = b.message_id
       ORDER BY b.created_at_ms DESC LIMIT 20"""
  ).fetchall()
  tags = conn.execute("SELECT * FROM tags ORDER BY name").fetchall()
  conn.close()

  return templates.TemplateResponse("dashboard.html", {
    "request": request,
    "total": total,
    "recent_searches": recent_searches,
    "bookmarks": bookmarks,
    "tags": tags
  })

@app.get("/search", response_class=HTMLResponse)
def search_page(request: Request):
  return templates.TemplateResponse("search.html", {"request": request, "results": []})

@app.post("/search", response_class=HTMLResponse)
def do_search(
  request: Request,
  mode: str = Form(...),
  query: str = Form(...),
  address: str = Form(""),
  msg_type: str = Form(""),
  thread_id: str = Form(""),
  date_from_ms: str = Form(""),
  date_to_ms: str = Form("")
):
  filters = {
    "address": address or None,
    "type": msg_type if msg_type != "" else None,
    "thread_id": thread_id or None,
    "date_from_ms": date_from_ms or None,
    "date_to_ms": date_to_ms or None
  }

  conn = connect()
  register_regex(conn)
  log_search(conn, mode, query, filters)
  results = run_search(conn, mode, query, filters, limit=200)
  conn.close()

  return templates.TemplateResponse("search.html", {
    "request": request,
    "results": results,
    "query": query,
    "mode": mode,
    "filters": filters
  })

@app.post("/bookmark")
def bookmark(message_id: int = Form(...), note: str = Form("")):
  conn = connect()
  conn.execute(
    "INSERT OR IGNORE INTO bookmarks(created_at_ms, message_id, note) VALUES (?,?,?)",
    (int(time.time() * 1000), message_id, note)
  )
  conn.commit()
  conn.close()
  return RedirectResponse("/dashboard", status_code=303)

@app.post("/tag")
def create_tag(name: str = Form(...)):
  conn = connect()
  conn.execute("INSERT OR IGNORE INTO tags(name) VALUES (?)", (name.strip(),))
  conn.commit()
  conn.close()
  return RedirectResponse("/dashboard", status_code=303)

@app.post("/saved-search")
def save_search(name: str = Form(...), mode: str = Form(...), query: str = Form(...)):
  conn = connect()
  conn.execute(
    "INSERT INTO saved_searches(name, created_at_ms, mode, query, filters_json) VALUES (?,?,?,?,?)",
    (name, int(time.time() * 1000), mode, query, "{}")
  )
  conn.commit()
  conn.close()
  return RedirectResponse("/dashboard", status_code=303)

@app.get("/export.csv")
def export_csv(mode: str, query: str):
  conn = connect()
  register_regex(conn)
  rows = run_search(conn, mode, query, {}, limit=5000)

  def gen():
    yield "id,address,date_ms,type,thread_id,body\n"
    for r in rows:
      body = (r["body"] or "").replace('"', '""').replace("\n", " ").replace("\r", " ")
      yield f'{r["id"]},"{r["address"]}",{r["date_ms"]},{r["type"]},{r["thread_id"]},"{body}"\n'
    conn.close()

  return StreamingResponse(gen(), media_type="text/csv")
