import threading
from datetime import datetime
from pathlib import Path

import uvicorn
from fastapi import FastAPI, UploadFile, File


class SharedDrive:
    def __init__(
        self,
        root_dir: str,
        host: str = "127.0.0.1",
        port: int = 8021
    ):
        print(f"----------- ProxyPass        /upload897h32d892189  http://127.0.0.1:8021/upload")
        print(f"----------- ProxyPassReverse /upload897h32d892189  http://127.0.0.1:8021/upload")
        
        self.root_dir = Path(root_dir)
        self.root_dir.mkdir(exist_ok=True)

        self.host = host
        self.port = port

        self.app = FastAPI()
        self._register_routes()

        self._start_server_thread()

    def _start_server_thread(self):
        thread = threading.Thread(
            target=self._run_server,
            daemon=True
        )
        thread.start()

    def _run_server(self):
        uvicorn.run(
            self.app,
            host=self.host,
            port=self.port,
            log_level="info"
        )

    def _generate_name(self, original_name: str) -> str:
        ext = Path(original_name).suffix
        now = datetime.now()
        timestamp = now.strftime("%Y%m%d_%H%M%S")
        millis = f"{int(now.microsecond / 1000):03d}"
        return f"{timestamp}_{millis}{ext}"

    def get_last_uploads(self, count: int):
        if count <= 0:
            raise Exception("Count must be greater than zero")

        files = sorted(
            (f for f in self.root_dir.iterdir() if f.is_file()),
            key=lambda p: p.name,
            reverse=True
        )

        if len(files) < count:
            raise Exception("Not enough uploads")

        return files[:count]

    def _register_routes(self):
        @self.app.post("/upload")
        async def upload(file: UploadFile = File(...)):
            target_name = self._generate_name(file.filename)
            target_path = self.root_dir / target_name

            size = 0

            with target_path.open("wb") as f:
                while True:
                    chunk = await file.read(1024 * 1024)
                    if not chunk:
                        break
                    f.write(chunk)
                    size += len(chunk)

            return {
                "target_name": target_name,
                "size": size
            }
