from flask import Flask, request, jsonify
import json
import random
import time
import requests
import threading
from queue import Queue
import logging
from datetime import datetime

app = Flask(__name__)

# Configure logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s'
)

# Load configuration
with open('config.json', 'r') as f:
    config = json.load(f)

class WorkerClient:
    def __init__(self, worker_config):
        self.config = worker_config
        self.busy = False
        self.last_health_check = None
        self.lock = threading.Lock()

    def is_healthy(self):
        try:
            response = requests.get(
                f"{self.config['endpoint']}/health",
                headers={"X-API-Key": self.config['api_key']},
                timeout=5
            )
            if response.status_code == 200:
                self.last_health_check = datetime.now()
                return True
        except:
            pass
        return False

    def scrape_url(self, url):
        try:
            response = requests.post(
                f"{self.config['endpoint']}/scrape",
                headers={"X-API-Key": self.config['api_key']},
                json={"url": url},
                timeout=30
            )
            if response.status_code == 200:
                return response.json()["data"]
        except Exception as e:
            logging.error(f"Error with worker {self.config['id']}: {str(e)}")
        return None

# Initialize worker pool
worker_pool = [WorkerClient(w) for w in config["workers"]]

def get_available_worker():
    available_workers = [w for w in worker_pool if not w.busy and w.is_healthy()]
    return random.choice(available_workers) if available_workers else None

@app.route('/scrape', methods=['POST'])
def scrape():
    data = request.get_json()
    if not data or 'url' not in data:
        return jsonify({"error": "No URL provided"}), 400
    
    url = data['url']
    worker = get_available_worker()
    
    if not worker:
        return jsonify({
            "error": "No workers available",
            "status": "error"
        }), 503
    
    with worker.lock:
        worker.busy = True
        try:
            logging.info(f"Worker {worker.config['id']} processing {url}")
            result = worker.scrape_url(url)
            
            if result:
                logging.info(f"Successfully scraped {url}")
                return jsonify({
                    "status": "success",
                    "data": result
                })
            else:
                logging.error(f"Failed to scrape {url}")
                return jsonify({
                    "status": "error",
                    "message": "Failed to scrape URL"
                }), 500
                
        except Exception as e:
            logging.error(f"Error processing {url}: {str(e)}")
            return jsonify({
                "status": "error",
                "message": str(e)
            }), 500
        finally:
            worker.busy = False

@app.route('/status', methods=['GET'])
def status():
    worker_statuses = [{
        "id": w.config["id"],
        "endpoint": w.config["endpoint"],
        "busy": w.busy,
        "healthy": w.is_healthy(),
        "last_health_check": w.last_health_check.isoformat() if w.last_health_check else None
    } for w in worker_pool]
    
    return jsonify({
        "workers": worker_statuses
    })

if __name__ == '__main__':
    app.run(
        host=config["server"]["host"],
        port=config["server"]["port"]
    )
