import requests
import base64
import os
import logging
from urllib.parse import quote

logger = logging.getLogger(__name__)

class GiteaAPI:
    def __init__(self, owner="butterfly", repo="ragdocs"):
        self.base_url = "https://git.client.guacamolebox.net/api/v1"
        self.owner = owner
        self.repo = repo
        # Hardcoded for portability in standalone binary
        self.token = "f8e1300d871e905e27ce54c3455a3343104d9b04"
        self.headers = {"Authorization": f"token {self.token}", "Content-Type": "application/json"}

    def delete_file(self, filepath, sha, branch="main", message="Automated Cleanup"):
        """Delete a file from the repository via the Gitea API."""
        url = f"{self.base_url}/repos/{self.owner}/{self.repo}/contents/{quote(filepath, safe='/')}"
        data = {
            "branch": branch,
            "sha": sha,
            "message": message
        }
        try:
            resp = requests.delete(url, headers=self.headers, json=data, timeout=15)
            if resp.status_code == 200:
                logger.info(f"Deleted remote file: {filepath}")
                return True
            else:
                logger.error(f"Failed to delete {filepath}: {resp.text}")
                return False
        except Exception as e:
            logger.error(f"Error deleting {filepath}: {e}")
            return False

    def list_files(self, path="", recursive=True):
        """Recursively list all files in the repository."""
        url = f"{self.base_url}/repos/{self.owner}/{self.repo}/contents/{quote(path, safe='/')}"
        try:
            resp = requests.get(url, headers=self.headers, timeout=15)
            if resp.status_code == 404:
                return []
            resp.raise_for_status()
            items = resp.json()
            
            # Gitea returns a list for directories, but a dict for single files
            if isinstance(items, dict):
                items = [items]
            
            files = []
            for item in items:
                if item["type"] == "file":
                    files.append({
                        "path": item["path"],
                        "download_url": item["download_url"],
                        "size": item["size"],
                        "sha": item["sha"]
                    })
                elif item["type"] == "dir" and recursive:
                    files.extend(self.list_files(item["path"], recursive=True))
            return files
        except Exception as e:
            logger.debug(f"Note: Failed to list files at {path}: {e}")
            return []

    def upload_file(self, local_path, remote_path, branch="main", message="Added new document"):
        """Upload a file to the repository via the Gitea API (POST for Create, PUT for Update)."""
        url = f"{self.base_url}/repos/{self.owner}/{self.repo}/contents/{quote(remote_path, safe='/')}"
        
        try:
            with open(local_path, "rb") as f:
                content = base64.b64encode(f.read()).decode("utf-8")
                
            # 1. Existing Check
            sha = None
            exists = False
            try:
                existing_resp = requests.get(url, headers=self.headers, timeout=10)
                if existing_resp.status_code == 200:
                    sha = existing_resp.json().get("sha")
                    exists = True
                elif existing_resp.status_code == 404:
                    exists = False
            except:
                exists = False # Assume new if check fails
                
            data = {
                "branch": branch,
                "content": content,
                "message": message
            }
            if sha:
                data["sha"] = sha
                
            # 2. Method selection (POST for Create, PUT for Update)
            method = requests.put if exists else requests.post
            resp = method(url, headers=self.headers, json=data, timeout=15)
            
            if resp.status_code not in [200, 201]:
                logger.error(f"Failed to upload {remote_path}: {resp.text}")
                return None
                
            return resp.json()["content"]["download_url"]
        except Exception as e:
            logger.error(f"Failed to upload {local_path} to {remote_path}: {e}")
            return None

    def download_file(self, remote_path, local_path, is_binary=True):
        """Download a file from the repository to a local path."""
        url = self.get_raw_url(remote_path)
        try:
            resp = requests.get(url, headers=self.headers, timeout=30)
            resp.raise_for_status()
            
            mode = "wb" if is_binary else "w"
            content = resp.content if is_binary else resp.text
            
            with open(local_path, mode) as f:
                f.write(content)
            logger.info(f"Downloaded {remote_path} to {local_path}")
            return True
        except Exception as e:
            logger.error(f"Failed to download {remote_path}: {e}")
            return False

    def get_raw_url(self, filepath, branch="main"):
        """Generate the raw URL for a given file path."""
        return f"https://git.client.guacamolebox.net/{self.owner}/{self.repo}/raw/branch/{branch}/{quote(filepath, safe='/')}"

if __name__ == "__main__":
    logging.basicConfig(level=logging.INFO)
    api = GiteaAPI()
    files = api.list_files()
    print(f"Found {len(files)} files.")
    for f in files[:3]:
        print(f" - {f['path']} at {f['download_url']}")
