import http.server
import socketserver
import threading
import time
import json
import urllib.parse
import argparse
import sys
from http import HTTPStatus
import requests

_is_jellyfin_scan_running = False
_stop_event = threading.Event()

def build_jellyfin_api_url(address, api_target, api_key):
    """Constructs the full Jellyfin API URL with the API key."""
    if not api_target.startswith('/'):
        api_target = '/' + api_target

    url = f"{address}{api_target}"
    params = {'api_key': api_key}
    return url + '?' + urllib.parse.urlencode(params)


def send_request(url, method='GET'):
    headers = {'User-Agent': 'None', 'Content-Type': 'application/json'}
    try:
        if method.upper() == 'POST':
            response = requests.post(url, headers=headers, data=json.dumps({}))
        else:
            response = requests.get(url, headers=headers)

        if response.status_code == HTTPStatus.OK:
            return response.text
        else:
            print(f"Request failed with status code {response.status_code} for URL: {url}")
            return None
    except requests.RequestException as e:
        print(f"An error occurred during the request to {url}: {e}")
        return None

def check_is_jellyfin_scan_running(config):
    """Continuously checks the status of the Jellyfin 'RefreshLibrary' scheduled task."""
    jellyfin_url = build_jellyfin_api_url(config.address, "/scheduledtasks", config.apikey)

    while not _stop_event.is_set():
        time.sleep(config.scan_interval)
        global _is_jellyfin_scan_running

        tasks_response = send_request(jellyfin_url, method='GET')

        if tasks_response:
            try:
                tasks_data = json.loads(tasks_response)
                status = None
                for task in tasks_data:
                    if task.get("Key") == "RefreshLibrary":
                        status = task.get("State")
                        break

                print(f"Jellyfin scan status: {status}")

                if status is None:
                    _is_jellyfin_scan_running = True
                    print("Warning: 'RefreshLibrary' task not found. Setting scan status to True.")
                else:
                    status = status.lower()
                    _is_jellyfin_scan_running = "running" in status or "cancelling" in status

            except json.JSONDecodeError:
                print("Error: Could not parse Jellyfin response JSON.")
                _is_jellyfin_scan_running = True
        else:
            _is_jellyfin_scan_running = True
            print("Warning: Jellyfin API request failed. Setting scan status to True.")


class RequestHandler(http.server.SimpleHTTPRequestHandler):
    def __init__(self, *args, **kwargs):
        self.config = kwargs.pop('config')
        super().__init__(*args, **kwargs)

    def do_GET(self):
        global _is_jellyfin_scan_running

        if "jellyfin" in self.path.lower():
            if _is_jellyfin_scan_running:
                message = "Jellyfin is currently running a scan."
                self.respond(message, HTTPStatus.OK)
            else:
                message = "Sending Jellyfin Library Update Scan Request"
                self.respond(message, HTTPStatus.OK)

                _is_jellyfin_scan_running = True

                jellyfin_url = build_jellyfin_api_url(self.config.address, self.config.api_target, self.config.apikey)
                threading.Thread(target=send_request, args=(jellyfin_url, 'POST')).start()

        else:
            message = "Endpoint not recognized."
            self.respond(message, HTTPStatus.NOT_FOUND)

    def do_POST(self):
        global _is_jellyfin_scan_running

        if "jellyfin" in self.path.lower():
            message = "Jellyfin scan requested (POST accepted)."
            self.respond(message, HTTPStatus.OK)

            # 2. Trigger the Jellyfin scan in the background
            # Note: We still set the status to True here to block concurrent GET requests
            _is_jellyfin_scan_running = True

            jellyfin_url = build_jellyfin_api_url(self.config.address, self.config.api_target, self.config.apikey)
            threading.Thread(target=send_request, args=(jellyfin_url, 'POST')).start()

        else:
            message = "Endpoint not recognized."
            self.respond(message, HTTPStatus.NOT_FOUND)

    def respond(self, message, status_code):
        """Helper to send the HTTP response."""
        self.send_response(status_code)
        self.send_header('Content-type', 'text/plain')
        self.end_headers()
        self.wfile.write(message.encode('utf-8'))

def run_server(config):
    """wrapper function to pass the configuration to the RequestHandler."""

    def handler_factory(*args, **kwargs):
        return RequestHandler(*args, config=config, **kwargs)

    with socketserver.TCPServer((config.host, config.port), handler_factory) as httpd:
        print(f"Serving HTTP on {config.host} port {config.port}...")
        httpd.serve_forever()


def main():
    parser = argparse.ArgumentParser(
        description="A proxy server to trigger a Jellyfin library scan only when no scan is running."
    )

    # Required arguments (single dash)
    parser.add_argument(
        '-a', '--address',
        required=True,
        help="The full base URL of the Jellyfin server (e.g., http://192.168.4.4:8096)"
    )
    parser.add_argument(
        '-k', '--apikey',
        required=True,
        help="The API key for accessing the Jellyfin server (e.g., test)"
    )

    # Optional arguments with defaults (single dash)
    parser.add_argument(
        '-t', '--api-target',
        type=str,
        default="/library/refresh",
        help="The Jellyfin API endpoint to call to trigger the scan. (Default: /library/refresh)"
    )
    parser.add_argument(
        '-i', '--scan-interval',
        type=int,
        default=3,
        help="The interval in seconds to check if a Jellyfin scan is running. (Default: 3000ms)"
    )
    parser.add_argument(
        '-H', '--host',
        type=str,
        default="127.0.0.1",
        help="The host IP address for the local proxy server to listen on. (Default: 127.0.0.1)"
    )
    parser.add_argument(
        '-p', '--port',
        type=int,
        default=5000,
        help="The port for the local proxy server to listen on. (Default: 5000)"
    )

    config = parser.parse_args()

    print("\n--- Configuration ---")
    print(f"Jellyfin Address: {config.address}")
    print(f"Jellyfin Scan Target: {config.api_target}")
    print(f"Proxy Host: {config.host}:{config.port}")
    print(f"Scan Check Interval: {config.scan_interval}ms")
    print("---------------------\n")
    scan_thread = threading.Thread(target=check_is_jellyfin_scan_running, args=(config,), daemon=True)
    try:
        scan_thread.start()
        time.sleep(config.scan_interval / 1000.0)
        run_server(config)
    except Exception as e:
        print(f"An error occurred: {e}")
    finally:
        _stop_event.set()
        if 'scan_thread' in locals() and scan_thread.is_alive():
            scan_thread.join()
        sys.exit(0)


if __name__ == "__main__":
    main()