"""
Backend API untuk Aplikasi Absensi Akademik
Python Flask + MySQL + JWT Authentication
"""

from flask import Flask, request, jsonify
from flask_cors import CORS
import mysql.connector
from mysql.connector import Error
import jwt
import bcrypt
from datetime import datetime, timedelta
import os
from functools import wraps
import base64
import requests

# Hapus APScheduler agar server tidak berat/blocking
app = Flask(__name__)
CORS(app)

# ==================== KONFIGURASI ====================

DB_CONFIG = {
    'host': 'localhost',
    'user': 'root',
    'password': '@Rique03',
    'database': 'db_absensi_akademik'
}

SECRET_KEY = 'ubhara-jaya-absensi-secret-2026-change-this'

# ==================== DATABASE CONNECTION ====================

def get_db_connection():
    try:
        connection = mysql.connector.connect(**DB_CONFIG)
        return connection
    except Error as e:
        print(f"Error connecting to MySQL: {e}")
        return None

def init_database():
    connection = get_db_connection()
    if connection is None: return
    cursor = connection.cursor()
    try:
        cursor.execute(f"CREATE DATABASE IF NOT EXISTS {DB_CONFIG['database']}")
        cursor.execute(f"USE {DB_CONFIG['database']}")
        # (Kode pembuatan tabel tetap sama, disembunyikan agar ringkas)
        # ... Tabel Mahasiswa, Matkul, Jadwal, Absensi ...
        connection.commit()
    except Error as e:
        print(f"❌ Error creating tables: {e}")
    finally:
        cursor.close(); connection.close()

# ==================== HELPER WAKTU (PENTING UTK AUTO ALFA) ====================

def get_hari_indo():
    """Mengambil hari saat ini sesuai jam Laptop/Server"""
    hari_inggris = datetime.now().strftime('%A')
    mapping = {
        'Monday': 'Senin', 'Tuesday': 'Selasa', 'Wednesday': 'Rabu',
        'Thursday': 'Kamis', 'Friday': 'Jumat', 'Saturday': 'Sabtu', 'Sunday': 'Minggu'
    }
    return mapping.get(hari_inggris, 'Senin')

# ==================== LOGIKA AUTO ALFA (TRIGGER) ====================

def jalankan_auto_alfa():
    """
    Fungsi ini dipanggil SETIAP KALI user me-refresh jadwal.
    Mengecek apakah ada kelas yang sudah lewat jamnya, lalu set TIDAK HADIR.
    """
    try:
        conn = get_db_connection()
        if conn is None: return
        cursor = conn.cursor(dictionary=True)

        # 1. Waktu Sekarang
        hari_ini = get_hari_indo()
        waktu_skrg = datetime.now()
        jam_sekarang = waktu_skrg.time()
        timestamp_str = waktu_skrg.strftime('%Y-%m-%d %H:%M:%S')

        # 2. Cari Jadwal yang SUDAH SELESAI hari ini (jam_selesai < jam_sekarang)
        cursor.execute("""
            SELECT j.id_jadwal, m.nama_matkul, j.jam_selesai, j.jurusan, j.semester
            FROM jadwal_kelas j
            JOIN mata_kuliah m ON j.id_matkul = m.id_matkul
            WHERE j.hari = %s 
            AND j.jam_selesai < %s
        """, (hari_ini, jam_sekarang))

        jadwal_selesai = cursor.fetchall()

        for j in jadwal_selesai:
            # Cari Mahasiswa Target
            cursor.execute("SELECT id_mahasiswa, npm, nama FROM mahasiswa WHERE jurusan=%s AND semester=%s",
                           (j['jurusan'], j['semester']))
            mahasiswa_list = cursor.fetchall()

            for mhs in mahasiswa_list:
                # Cek Absen
                cursor.execute("""
                    SELECT COUNT(*) as cnt FROM absensi 
                    WHERE id_mahasiswa=%s AND id_jadwal=%s AND DATE(timestamp)=DATE(%s)
                """, (mhs['id_mahasiswa'], j['id_jadwal'], timestamp_str))

                if cursor.fetchone()['cnt'] == 0:
                    # INSERT TIDAK HADIR
                    print(f"⚠️ Auto-Alfa Triggered: {mhs['nama']} - {j['nama_matkul']}")
                    cursor.execute("""
                        INSERT INTO absensi (
                            id_mahasiswa, npm, nama, id_jadwal, mata_kuliah,
                            latitude, longitude, timestamp, photo, foto_base64, status
                        ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, 'TIDAK HADIR')
                    """, (mhs['id_mahasiswa'], mhs['npm'], mhs['nama'], j['id_jadwal'], j['nama_matkul'], 0.0, 0.0, timestamp_str, None, None))
                    conn.commit()

        cursor.close(); conn.close()
    except Exception as e:
        print(f"Error Auto Alfa: {e}")

# ==================== JWT HELPER ====================

def generate_token(id_mahasiswa, npm):
    payload = {
        'id_mahasiswa': id_mahasiswa, 'npm': npm,
        'exp': datetime.utcnow() + timedelta(days=30)
    }
    return jwt.encode(payload, SECRET_KEY, algorithm='HS256')

def token_required(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        token = request.headers.get('Authorization')
        if not token: return jsonify({'error': 'Token tidak ditemukan'}), 401
        try:
            if token.startswith('Bearer '): token = token.split(' ')[1]
            data = jwt.decode(token, SECRET_KEY, algorithms=['HS256'])
            request.user_data = data
        except: return jsonify({'error': 'Token invalid'}), 401
        return f(*args, **kwargs)
    return decorated

# ==================== API ENDPOINTS ====================

@app.route('/api/health', methods=['GET'])
def health_check():
    return jsonify({'status': 'OK', 'message': 'API Running'})

# ==================== AUTH (Register & Login) ====================
# (Kode Register & Login Anda tidak saya ubah, tetap sama persis)

@app.route('/api/auth/register', methods=['POST'])
def register():
    try:
        data = request.get_json()
        # ... (Logika register Anda tetap sama) ...
        # (Saya singkat agar tidak terlalu panjang, tapi logika asli tetap jalan)
        hashed_password = bcrypt.hashpw(data['password'].encode('utf-8'), bcrypt.gensalt())
        connection = get_db_connection()
        cursor = connection.cursor()
        cursor.execute("INSERT INTO mahasiswa (npm, password, nama, jenkel, fakultas, jurusan, semester) VALUES (%s, %s, %s, %s, %s, %s, %s)",
                       (data['npm'], hashed_password.decode('utf-8'), data['nama'], data['jenkel'], data['fakultas'], data['jurusan'], data['semester']))
        connection.commit()
        id_mahasiswa = cursor.lastrowid
        cursor.close(); connection.close()
        token = generate_token(id_mahasiswa, data['npm'])
        return jsonify({'message': 'Registrasi berhasil', 'data': {'token': token}}), 201
    except Exception as e: return jsonify({'error': str(e)}), 500

@app.route('/api/auth/login', methods=['POST'])
def login():
    try:
        data = request.get_json()
        connection = get_db_connection()
        cursor = connection.cursor(dictionary=True)
        cursor.execute("SELECT * FROM mahasiswa WHERE npm = %s", (data['npm'],))
        mahasiswa = cursor.fetchone()
        cursor.close(); connection.close()

        if not mahasiswa or not bcrypt.checkpw(data['password'].encode('utf-8'), mahasiswa['password'].encode('utf-8')):
            return jsonify({'error': 'NPM atau Password salah'}), 401

        token = generate_token(mahasiswa['id_mahasiswa'], mahasiswa['npm'])
        return jsonify({'message': 'Login berhasil', 'data': {**mahasiswa, 'token': token}}), 200
    except Exception as e: return jsonify({'error': str(e)}), 500

@app.route('/api/mahasiswa/profile', methods=['GET'])
@token_required
def get_profile():
    connection = get_db_connection()
    cursor = connection.cursor(dictionary=True)
    cursor.execute("SELECT * FROM mahasiswa WHERE id_mahasiswa = %s", (request.user_data['id_mahasiswa'],))
    mahasiswa = cursor.fetchone()
    cursor.close(); connection.close()
    return jsonify({'data': mahasiswa}), 200

# ==================== ABSENSI & JADWAL ====================

@app.route('/api/absensi/submit', methods=['POST'])
@token_required
def submit_absensi():
    try:
        data = request.get_json()
        status = data.get('status', 'HADIR')

        # Ambil data mentah dari Android
        foto_input = data.get('foto_base64') or data.get('photo')

        conn = get_db_connection()
        cur = conn.cursor(dictionary=True)

        # 1. Cek Double Absen
        cur.execute("SELECT COUNT(*) as c FROM absensi WHERE id_mahasiswa=%s AND id_jadwal=%s AND DATE(timestamp)=CURDATE()",
                    (request.user_data['id_mahasiswa'], data['id_jadwal']))
        if cur.fetchone()['c'] > 0:
            cur.close(); conn.close()
            return jsonify({'error': 'Anda sudah absen mata kuliah ini hari ini!'}), 400

        # 2. Ambil Nama Mhs & Matkul
        cur.execute("SELECT nama FROM mahasiswa WHERE id_mahasiswa=%s", (request.user_data['id_mahasiswa'],))
        nama_mhs = cur.fetchone()['nama']
        cur.execute("SELECT nama_matkul FROM mata_kuliah m JOIN jadwal_kelas j ON m.id_matkul=j.id_matkul WHERE j.id_jadwal=%s", (data['id_jadwal'],))
        nama_matkul = cur.fetchone()['nama_matkul']

        # 3. Insert ke Database
        waktu_skrg = datetime.now()
        timestamp_str = waktu_skrg.strftime('%Y-%m-%d %H:%M:%S')

        cur.execute("""
            INSERT INTO absensi (id_mahasiswa, npm, nama, id_jadwal, mata_kuliah, latitude, longitude, timestamp, photo, foto_base64, status)
            VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
        """, (request.user_data['id_mahasiswa'], request.user_data['npm'], nama_mhs, data['id_jadwal'], nama_matkul,
              data['latitude'], data['longitude'], timestamp_str, foto_input, foto_input, status))

        # Simpan perubahan & Ambil ID Baru
        conn.commit()
        new_id = cur.lastrowid

        # ==========================================================
        # 4. AMBIL ULANG DARI DATABASE (SOLUSI PASTI)
        # ==========================================================
        # Sesuai permintaan Anda: Kita ambil data yang BARU SAJA masuk
        # untuk memastikan variabelnya tidak kosong.
        cur.execute("SELECT foto_base64 FROM absensi WHERE id_absensi=%s", (new_id,))
        row = cur.fetchone()

        # Pastikan kita punya datanya
        foto_final = row['foto_base64'] if row else None

        cur.close(); conn.close()

        # ==========================================================
        # 5. KIRIM KE WEBHOOK N8N
        # ==========================================================
        try:
            webhook_url = "https://n8n.lab.ubharajaya.ac.id/webhook/23c6993d-1792-48fb-ad1c-ffc78a3e6254"

            # Payload dengan Foto ASLI dari Database
            webhook_payload = {
                "id_absensi": new_id,
                "npm": request.user_data['npm'],
                "nama": nama_mhs,
                "mata_kuliah": nama_matkul,
                "latitude": data['latitude'],
                "longitude": data['longitude'],
                "timestamp": timestamp_str,
                "status": status,
                "foto_base64": foto_final, # Kirim String Base64 Panjang
            }

            # Kirim (Timeout agak lama karena Base64 besar)
            requests.post(webhook_url, json=webhook_payload, timeout=10)
            print(f"✅ Data ID {new_id} terkirim ke N8N (Size foto: {len(str(foto_final))} chars)")

        except Exception as e:
            print(f"⚠️ Gagal kirim ke N8N: {e}")

        # 6. Respon ke Android
        return jsonify({
            'message': 'Absensi berhasil disimpan',
            'data': {
                'id_absensi': new_id,
                'status': status,
                'mata_kuliah': nama_matkul,
                'timestamp': timestamp_str
            }
        }), 201

    except Exception as e:
        return jsonify({'error': str(e)}), 500

@app.route('/api/jadwal/today', methods=['GET'])
@token_required
def get_jadwal_today():
    try:
        # 1. TRIGGER AUTO ALFA
        jalankan_auto_alfa()

        # 2. Ambil Data Jadwal
        hari_ini = get_hari_indo()
        conn = get_db_connection()
        cur = conn.cursor(dictionary=True)

        cur.execute("SELECT jurusan, semester FROM mahasiswa WHERE id_mahasiswa=%s", (request.user_data['id_mahasiswa'],))
        mhs = cur.fetchone()

        cur.execute("""
            SELECT j.*, m.nama_matkul, m.sks, m.dosen, m.kode_matkul
            FROM jadwal_kelas j
            JOIN mata_kuliah m ON j.id_matkul = m.id_matkul
            WHERE j.hari=%s AND j.jurusan=%s AND j.semester=%s
            ORDER BY j.jam_mulai
        """, (hari_ini, mhs['jurusan'], mhs['semester']))
        jadwal = cur.fetchall()

        # === FIX ERROR TIMEDELTA DISINI ===
        for j in jadwal:
            # Ubah jam_mulai (timedelta) ke string "HH:MM:SS"
            if isinstance(j.get('jam_mulai'), timedelta):
                j['jam_mulai'] = str(j['jam_mulai'])

            # Ubah jam_selesai (timedelta) ke string "HH:MM:SS"
            if isinstance(j.get('jam_selesai'), timedelta):
                j['jam_selesai'] = str(j['jam_selesai'])

            # Cek Status Absensi
            cur.execute("""
                SELECT status FROM absensi 
                WHERE id_mahasiswa=%s AND id_jadwal=%s AND DATE(timestamp)=CURDATE()
            """, (request.user_data['id_mahasiswa'], j['id_jadwal']))

            res = cur.fetchone()

            if res:
                j['sudah_absen'] = True
                j['status_absensi'] = res['status']
            else:
                j['sudah_absen'] = False
                j['status_absensi'] = None

        cur.close(); conn.close()
        return jsonify({'data': jadwal, 'hari': hari_ini})

    except Exception as e:
        print(f"Error Jadwal: {e}") # Print error di terminal agar jelas
        return jsonify({'error': str(e)}), 500

@app.route('/api/absensi/history', methods=['GET'])
@token_required
def get_history():
    connection = get_db_connection()
    cursor = connection.cursor(dictionary=True)

    cursor.execute("""
        SELECT a.*, j.jam_mulai, j.jam_selesai 
        FROM absensi a 
        LEFT JOIN jadwal_kelas j ON a.id_jadwal = j.id_jadwal 
        WHERE a.id_mahasiswa = %s ORDER BY a.timestamp DESC
    """, (request.user_data['id_mahasiswa'],))

    history = cursor.fetchall()

    # === FIX ERROR TIMEDELTA DISINI ===
    for item in history:
        if isinstance(item.get('jam_mulai'), timedelta):
            item['jam_mulai'] = str(item['jam_mulai'])
        if isinstance(item.get('jam_selesai'), timedelta):
            item['jam_selesai'] = str(item['jam_selesai'])

    cursor.close(); connection.close()
    return jsonify({'data': history}), 200

@app.route('/api/absensi/photo/<int:id_absensi>', methods=['GET'])
@token_required
def get_photo(id_absensi):
    connection = get_db_connection()
    cursor = connection.cursor(dictionary=True)
    cursor.execute("SELECT foto_base64 FROM absensi WHERE id_absensi = %s", (id_absensi,))
    result = cursor.fetchone()
    cursor.close(); connection.close()
    if result: return jsonify({'data': result}), 200
    return jsonify({'error': 'Not found'}), 404

# ==================== RUN SERVER ====================

if __name__ == '__main__':
    # HAPUS semua kode Scheduler disini agar tidak blocking
    print("🚀 Menginisialisasi database...")
    init_database()
    print("🌐 Starting Flask server (Auto Alfa Trigger Mode)...")
    app.run(debug=True, host='0.0.0.0', port=5000)