from flask import Flask, jsonify, request
from flask_cors import CORS
import psycopg2
import psycopg2.extras
import json

app = Flask(__name__)
# Mengizinkan semua origin (termasuk port 5173 milik React) untuk mengakses API
CORS(app, resources={r"/api/*": {"origins": "*"}})

# =========================================================================
# KONEKSI DATABASE NEON (SERVERLESS POSTGRESQL)
# =========================================================================
# Ganti string di bawah ini dengan Connection String asli dari dashboard Neon kamu!
NEON_DB_URI = "postgresql://neondb_owner:npg_l27gXGaeChPq@ep-quiet-morning-aobokj6d.c-2.ap-southeast-1.aws.neon.tech/neondb?sslmode=require"

def get_db_connection():
    return psycopg2.connect(NEON_DB_URI)

def generate_next_id(prefix, table_name):
    """Mencari akhiran ID numerik tertinggi secara aman menggunakan Tuple index"""
    conn = None
    cursor = None
    try:
        conn = get_db_connection()
        cursor = conn.cursor() # Menggunakan cursor biasa (tuple) agar lebih aman & cepat
        cursor.execute(f"SELECT id FROM {table_name} ORDER BY id DESC LIMIT 1")
        row = cursor.fetchone()
        
        if not row or row[0] is None:
            return f"{prefix}001"
        
        # Ambil string ID (misal 'RI001' atau 'P003') dari index ke-0 tuple
        last_id = str(row[0])
        current_num = int(''.join(filter(str.isdigit, last_id)))
        next_num = current_num + 1
        return f"{prefix}{next_num:03d}"
    except Exception as e:
        print(f"Error generating ID untuk {table_name}: {e}")
        import random
        return f"{prefix}{random.randint(100, 999)}"
    finally:
        if cursor: cursor.close()
        if conn: conn.close()

# =========================================================================
# API ENDPOINTS (GET METHOD)
# =========================================================================

@app.route('/api/jalan', methods=['GET'])
def get_jalan():
    conn = get_db_connection()
    cursor = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor)
    
    # Mengambil field panjang yang sekarang sudah terisi otomatis dalam satuan meter
    cursor.execute("SELECT id, nama, status, panjang, ST_AsGeoJSON(geom) as geom_json FROM jalan")
    rows = cursor.fetchall()
    
    for row in rows:
        if row['geom_json']:
            row['geom'] = json.loads(row['geom_json'])
        del row['geom_json']
        
        # Opsional: Membulatkan nilai panjang jalan menjadi 2 angka di belakang koma demi estetika UI
        if row['panjang'] is not None:
            row['panjang'] = round(row['panjang'], 2)
            
    cursor.close()
    conn.close()
    return jsonify(rows)

@app.route('/api/area', methods=['GET'])
def get_area():
    conn = get_db_connection()
    cursor = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor)
    
    # Mengambil semua field data area dari database
    cursor.execute("SELECT id, nama, luas, ST_AsGeoJSON(geom) as geom_json FROM area")
    rows = cursor.fetchall()
    
    for row in rows:
        if row['geom_json']:
            row['geom'] = json.loads(row['geom_json'])
        del row['geom_json']
        
        # Opsional: Membulatkan nilai luas wilayah menjadi 2 angka di belakang koma untuk merapikan UI
        if row['luas'] is not None:
            row['luas'] = round(row['luas'], 2)
            
    cursor.close()
    conn.close()
    return jsonify(rows)

@app.route('/api/ibadah', methods=['GET'])
def get_ibadah():
    conn = get_db_connection()
    cursor = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor)
    cursor.execute("SELECT id, nama, jenis, kontak, radius, ST_AsGeoJSON(geom) as geom_json FROM rumah_ibadah")
    rows = cursor.fetchall()
    
    for row in rows:
        if row['geom_json']:
            row['geom'] = json.loads(row['geom_json'])
        del row['geom_json']
        
    cursor.close()
    conn.close()
    return jsonify(rows)

@app.route('/api/miskin', methods=['GET'])
def get_miskin():
    conn = get_db_connection()
    cursor = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor)
    
    try:
        cursor.execute("""
            SELECT id, kepala_keluarga, jumlah_anggota, status_bantuan, jenis_bantuan, id_ibadah_terdekat, 
                   ST_AsGeoJSON(geom) as geom_json 
            FROM penduduk_miskin
        """)
        rows = cursor.fetchall()
        
        for row in rows:
            if row['geom_json']:
                row['geom'] = json.loads(row['geom_json'])
            del row['geom_json']
            
            # Memisahkan kembali string koma menjadi Array murni untuk kebutuhan state di React
            if row['jenis_bantuan']:
                row['jenis_bantuan'] = [b.strip() for b in row['jenis_bantuan'].split(',')]
            else:
                row['jenis_bantuan'] = []
                
        response = rows
    except Exception as e:
        response = {"status": "error", "message": str(e)}
        print(f"ERROR: Failed to fetch penduduk miskin: {e}")
    finally:
        cursor.close()
        conn.close()
        
    return jsonify(response)

# =========================================================================
# API ENDPOINTS (POST METHOD)
# =========================================================================

@app.route('/api/ibadah/create', methods=['POST'])
def create_ibadah():
    data = request.json
    next_id = generate_next_id('RI', 'rumah_ibadah')
    
    conn = get_db_connection()
    cursor = conn.cursor()
    
    query = """
        INSERT INTO rumah_ibadah (id, nama, jenis, kontak, radius, geom)
        VALUES (%s, %s, %s, %s, %s, ST_GeomFromText(%s, 4326))
    """
    wkt_point = f"POINT({data['lng']} {data['lat']})"
    
    try:
        cursor.execute(query, (
            next_id, 
            data['nama'], 
            data['jenis'], 
            data.get('kontak', ''),  # Menangani jika kontak kosong
            int(data['radius']), 
            wkt_point
        ))
        conn.commit()
        response = {"status": "success", "generated_id": next_id}
        print("SUCCESS: Rumah ibadah successfully saved to database!")
    except Exception as e:
        conn.rollback()
        response = {"status": "error", "message": str(e)}
        print(f"ERROR: Rumah ibadah insertion failed: {e}")
    finally:
        cursor.close()
        conn.close()
        
    return jsonify(response)

@app.route('/api/miskin/create', methods=['POST'])
def create_miskin():
    data = request.json
    next_id = generate_next_id('P', 'penduduk_miskin')
    wkt_point = f"POINT({data['lng']} {data['lat']})"
    
    conn = get_db_connection()
    cursor = conn.cursor()
    
    query = """
        INSERT INTO penduduk_miskin (id, kepala_keluarga, jumlah_anggota, status_bantuan, jenis_bantuan, id_ibadah_terdekat, geom)
        VALUES (
            %s, %s, %s, %s, %s, 
            (SELECT id FROM rumah_ibadah ORDER BY geom::geography <-> ST_GeomFromText(%s, 4326)::geography LIMIT 1), 
            ST_GeomFromText(%s, 4326)
        )
        RETURNING id_ibadah_terdekat;
    """
    
    # Mengubah array Python ['PKH', 'BPJS_Kesehatan'] menjadi gabungan string 'PKH,BPJS_Kesehatan'
    if isinstance(data.get('jenis_bantuan'), list):
        jenis_bantuan_str = ",".join(data['jenis_bantuan'])
    else:
        jenis_bantuan_str = data.get('jenis_bantuan', '')
    
    try:
        cursor.execute(query, (
            next_id, 
            data['kepala_keluarga'], 
            data['jumlah_anggota'], 
            data['status_bantuan'], 
            jenis_bantuan_str, 
            wkt_point, 
            wkt_point
        ))
        
        # Mengambil ID rumah ibadah terdekat yang berhasil dihitung otomatis oleh PostGIS
        closest_ibadah_id = cursor.fetchone()[0]
        conn.commit()
        
        response = {
            "status": "success", 
            "generated_id": next_id, 
            "closest_hub": closest_ibadah_id,
            "message": "Data penduduk miskin berhasil disimpan"
        }
        print("SUCCESS: Penduduk miskin successfully saved to database!")
        
    except Exception as e:
        conn.rollback()
        response = {"status": "error", "message": str(e)}
        print(f"ERROR: Penduduk miskin insertion failed: {e}")
        
    finally:
        cursor.close()
        conn.close()
        
    return jsonify(response)

@app.route('/api/jalan/create', methods=['POST'])
def create_jalan():
    data = request.json
    conn = get_db_connection()
    cursor = conn.cursor()

    coords_str = ", ".join([f"{pt[1]} {pt[0]}" for pt in data['coords']])
    wkt_line = f"LINESTRING({coords_str})"

    # MENGGUNAKAN ST_Length agar kolom panjang (double precision) terisi otomatis dengan angka murni meter
    query = """
        INSERT INTO jalan (nama, status, panjang, geom)
        VALUES (
            %s, 
            %s, 
            ST_Length(ST_GeomFromText(%s, 4326)::geography), 
            ST_GeomFromText(%s, 4326)
        )
    """
    
    try:
        # Kita passing wkt_line dua kali (untuk hitung panjang dan untuk geometri)
        cursor.execute(query, (data['nama'], data['status'], wkt_line, wkt_line))
        conn.commit()
        response = {"status": "success", "message": "Jalan successfully created"}
        print("SUCCESS: Jalan successfully saved to database!")
    except Exception as e:
        conn.rollback()
        response = {"status": "error", "message": str(e)}
        print(f"ERROR: Jalan insertion failed: {e}")
    finally:
        cursor.close()
        conn.close()
        
    return jsonify(response)

@app.route('/api/area/create', methods=['POST'])
def create_area():
    data = request.json
    conn = get_db_connection()
    cursor = conn.cursor()

    coords = list(data['coords'])
    if coords[0] != coords[-1]:
        coords.append(coords[0])

    coords_str = ", ".join([f"{pt[1]} {pt[0]}" for pt in coords])
    wkt_poly = f"POLYGON(({coords_str}))"

    # We use exactly two %s because both ST_Area and ST_GeomFromText 
    # will read from the same exact wkt_poly variable we pass in.
    query = """
        INSERT INTO area (nama, luas, geom)
        VALUES (
            %s, 
            ST_Area(ST_GeomFromText(%s, 4326)::geography), 
            ST_GeomFromText(%s, 4326)
        )
    """
    
    try:
        cursor.execute(query, (data['nama'], wkt_poly, wkt_poly))
        conn.commit()
        response = {"status": "success", "message": "Area successfully created"}
        # GANTI DARI EMOJI JADI TEKS BIASA BIAR TERMINAL WINDOWS TIDAK CRASH:
        print("SUCCESS: Area successfully saved to database!")
    except Exception as e:
        conn.rollback()
        response = {"status": "error", "message": str(e)}
        # GANTI JUGA YANG INI:
        print(f"ERROR: Database insertion failed: {e}")
    finally:
        cursor.close()
        conn.close()
        
    return jsonify(response)

if __name__ == '__main__':
    app.run(
        host='0.0.0.0',
        port=5000,
        debug=False
    )