import http.server
import socketserver
import json
import urllib.request
import urllib.parse
import os
import sys

PORT = 8124
HA_CONFIG_ENTRIES_PATH = '/home/jesus/homeassistant/.storage/core.config_entries'
HA_STATUS_JSON_PATH = '/home/jesus/homeassistant/cf_status.json'
HA_TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhMjlhZDk5OGU5ZjE0NWRmYWY2NDRjMzY5ZGQyMjBiYyIsImlhdCI6MTY5MzgyNDk2MiwiZXhwIjoyMDA5MTg0OTYyfQ.JQJLsqxkNx_mM70t2vssGRGZiBqDrN4I_G89WBdtwB4"
HA_BASE_URL = "http://192.168.1.120:8123"
API_TOKEN = "6iX6sF3lgkFzVrq_8mockxvTZSkY2dOVgTGTGIZy"

def get_public_ip():
    try:
        with urllib.request.urlopen("https://api.ipify.org", timeout=5) as resp:
            return resp.read().decode('utf-8').strip()
    except:
        return "Unknown"

def get_ha_cf_entries():
    try:
        with open(HA_CONFIG_ENTRIES_PATH, 'r', encoding='utf-8') as f:
            data = json.load(f)
        cf_entries = [e for e in data['data']['entries'] if e.get('domain') == 'cloudflare']
        return data, cf_entries
    except:
        return {"data": {"entries": []}}, []

def save_ha_config_entries(data):
    try:
        with open(HA_CONFIG_ENTRIES_PATH, 'w', encoding='utf-8') as f:
            json.dump(data, f, indent=2, ensure_ascii=False)
        return True
    except Exception as ex:
        print("Save error:", ex)
        return False

def get_all_cf_zones():
    headers = {"Authorization": f"Bearer {API_TOKEN}", "Content-Type": "application/json"}
    try:
        req = urllib.request.Request("https://api.cloudflare.com/client/v4/zones", headers=headers)
        with urllib.request.urlopen(req, timeout=10) as resp:
            data = json.loads(resp.read().decode('utf-8'))
            return {z['name']: z['id'] for z in data.get('result', [])}
    except Exception as ex:
        print(f"Error fetching zones: {ex}")
        return {}

def get_cf_dns_records(zone_id):
    headers = {"Authorization": f"Bearer {API_TOKEN}", "Content-Type": "application/json"}
    try:
        req_dns = urllib.request.Request(f"https://api.cloudflare.com/client/v4/zones/{zone_id}/dns_records?per_page=100", headers=headers)
        with urllib.request.urlopen(req_dns, timeout=10) as resp:
            dns_data = json.loads(resp.read().decode('utf-8'))
            return dns_data.get('result', [])
    except Exception as ex:
        print(f"Error fetching DNS records: {ex}")
        return []

def get_full_state():
    full_data, cf_entries = get_ha_cf_entries()
    zones_map = get_all_cf_zones()
    public_ip = get_public_ip()

    # Map of all active DDNS records by zone
    ha_monitored_by_zone = {}
    for entry in cf_entries:
        z = entry['data'].get('zone')
        recs = entry['data'].get('records', [])
        ha_monitored_by_zone[z] = recs

    zones_list = []
    for z_name, z_id in zones_map.items():
        records = get_cf_dns_records(z_id)
        monitored = ha_monitored_by_zone.get(z_name, [])

        records_data = []
        for r in records:
            if r['type'] in ['A', 'CNAME']:
                is_ddns = r['name'] in monitored
                # Check if it's OCI / external IP
                is_oci = "158.179" in str(r['content'])
                records_data.append({
                    "id": r['id'],
                    "name": r['name'],
                    "type": r['type'],
                    "content": r['content'],
                    "proxied": r['proxied'],
                    "is_ddns": is_ddns,
                    "is_oci": is_oci
                })

        zones_list.append({
            "name": z_name,
            "id": z_id,
            "records": records_data,
            "monitored_count": len(monitored)
        })

    return {
        "status": "success",
        "public_ip": public_ip,
        "zones": zones_list
    }

class CFHandler(http.server.BaseHTTPRequestHandler):
    def end_headers(self):
        self.send_header('Access-Control-Allow-Origin', '*')
        self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
        self.send_header('Access-Control-Allow-Headers', 'Content-Type')
        super().end_headers()

    def do_OPTIONS(self):
        self.send_response(200)
        self.end_headers()

    def do_GET(self):
        if self.path.startswith('/api/status'):
            self.send_response(200)
            self.send_header('Content-Type', 'application/json; charset=utf-8')
            self.end_headers()
            data = get_full_state()
            self.wfile.write(json.dumps(data, ensure_ascii=False).encode('utf-8'))
        else:
            self.send_response(404)
            self.end_headers()

    def do_POST(self):
        content_length = int(self.headers.get('Content-Length', 0))
        body = self.rfile.read(content_length)
        payload = json.loads(body.decode('utf-8')) if body else {}

        if self.path == '/api/toggle':
            domain = payload.get('domain', '').strip().lower()
            enabled = payload.get('enabled', False)
            zone_name = payload.get('zone', '').strip().lower()
            
            full_data, cf_entries = get_ha_cf_entries()
            matched_entry = None
            for e in cf_entries:
                if e['data'].get('zone') == zone_name:
                    matched_entry = e
                    break

            if not matched_entry and enabled:
                import uuid
                matched_entry = {
                    "entry_id": uuid.uuid4().hex,
                    "version": 1,
                    "minor_version": 1,
                    "domain": "cloudflare",
                    "title": zone_name,
                    "data": {"api_token": API_TOKEN, "zone": zone_name, "records": []},
                    "options": {},
                    "pref_disable_new_entities": False,
                    "pref_disable_polling": False,
                    "source": "user",
                    "unique_id": None,
                    "disabled_by": None
                }
                full_data['data']['entries'].append(matched_entry)
                cf_entries.append(matched_entry)

            if matched_entry:
                recs = matched_entry['data'].get('records', [])
                if enabled and domain not in recs:
                    recs.append(domain)
                elif not enabled and domain in recs:
                    recs.remove(domain)
                matched_entry['data']['records'] = recs
                save_ha_config_entries(full_data)

            self.send_response(200)
            self.send_header('Content-Type', 'application/json; charset=utf-8')
            self.end_headers()
            self.wfile.write(json.dumps({"status": "ok", "domain": domain, "enabled": enabled}).encode('utf-8'))

        elif self.path == '/api/update_now':
            full_data, cf_entries = get_ha_cf_entries()
            zones_map = get_all_cf_zones()
            public_ip = get_public_ip()
            updated_records = []

            for entry in cf_entries:
                z_name = entry['data'].get('zone')
                z_records = entry['data'].get('records', [])
                z_id = zones_map.get(z_name)
                if z_id and public_ip != "Unknown":
                    dns_records = get_cf_dns_records(z_id)
                    for r_name in z_records:
                        matched = [cr for cr in dns_records if cr['name'] == r_name and cr['type'] == 'A']
                        for m in matched:
                            if m['content'] != public_ip:
                                # Update
                                headers = {"Authorization": f"Bearer {API_TOKEN}", "Content-Type": "application/json"}
                                url = f"https://api.cloudflare.com/client/v4/zones/{z_id}/dns_records/{m['id']}"
                                req = urllib.request.Request(url, data=json.dumps({"type":"A","name":r_name,"content":public_ip,"proxied":m['proxied']}).encode('utf-8'), headers=headers, method='PATCH')
                                urllib.request.urlopen(req, timeout=5)
                                updated_records.append(f"{r_name} -> {public_ip}")
                            else:
                                updated_records.append(f"{r_name} (al d??a)")

            self.send_response(200)
            self.send_header('Content-Type', 'application/json; charset=utf-8')
            self.end_headers()
            self.wfile.write(json.dumps({"status": "ok", "public_ip": public_ip, "updated": updated_records}).encode('utf-8'))
        else:
            self.send_response(404)
            self.end_headers()

if __name__ == '__main__':
    with socketserver.TCPServer(("", PORT), CFHandler) as httpd:
        print(f"Cloudflare Manager API Server running on port {PORT}...")
        httpd.serve_forever()
