from flask import render_template, redirect, url_for, flash, request, g
from app.admin import admin_bp
from app.auth.decorators import role_required, tenant_query, validate_tenant_resource
from app.models import User, Kelas, KelasMurid, MataPelajaran, Jadwal
from app.extensions import db
from datetime import time


@admin_bp.route('/')
@role_required('admin')
def dashboard():
    guru_count = tenant_query(User).filter_by(role='guru').count()
    murid_count = tenant_query(User).filter_by(role='murid').count()
    kelas_count = tenant_query(Kelas).count()
    mapel_count = tenant_query(MataPelajaran).count()
    jadwal_count = tenant_query(Jadwal).count()
    recent_guru = tenant_query(User).filter_by(role='guru').order_by(User.created_at.desc()).limit(5).all()
    recent_murid = tenant_query(User).filter_by(role='murid').order_by(User.created_at.desc()).limit(5).all()
    return render_template('admin/dashboard.html',
                           guru_count=guru_count, murid_count=murid_count,
                           kelas_count=kelas_count, mapel_count=mapel_count,
                           jadwal_count=jadwal_count,
                           recent_guru=recent_guru, recent_murid=recent_murid)


# ==================== GURU CRUD ====================

@admin_bp.route('/guru')
@role_required('admin')
def guru_list():
    guru = tenant_query(User).filter_by(role='guru').order_by(User.name).all()
    return render_template('admin/guru_list.html', guru_list=guru)


@admin_bp.route('/guru/tambah', methods=['GET', 'POST'])
@role_required('admin')
def guru_add():
    if request.method == 'POST':
        email = request.form['email']
        if User.query.filter_by(email=email).first():
            flash('Email sudah digunakan.', 'error')
            return render_template('admin/guru_form.html', edit=False)
        guru = User(
            school_id=g.school_id,
            name=request.form['name'],
            email=email,
            role='guru'
        )
        guru.set_password(request.form['password'])
        db.session.add(guru)
        db.session.commit()
        flash('Guru berhasil ditambahkan.', 'success')
        return redirect(url_for('admin.guru_list'))
    return render_template('admin/guru_form.html', edit=False)


@admin_bp.route('/guru/<int:id>/edit', methods=['GET', 'POST'])
@role_required('admin')
def guru_edit(id):
    guru = validate_tenant_resource(User.query.get(id))
    if request.method == 'POST':
        email = request.form['email']
        existing = User.query.filter_by(email=email).first()
        if existing and existing.id != guru.id:
            flash('Email sudah digunakan.', 'error')
            return render_template('admin/guru_form.html', edit=True, guru=guru)
        guru.name = request.form['name']
        guru.email = email
        if request.form.get('password'):
            guru.set_password(request.form['password'])
        db.session.commit()
        flash('Data guru berhasil diperbarui.', 'success')
        return redirect(url_for('admin.guru_list'))
    return render_template('admin/guru_form.html', edit=True, guru=guru)


@admin_bp.route('/guru/<int:id>/delete', methods=['POST'])
@role_required('admin')
def guru_delete(id):
    guru = validate_tenant_resource(User.query.get(id))
    db.session.delete(guru)
    db.session.commit()
    flash('Guru berhasil dihapus.', 'success')
    return redirect(url_for('admin.guru_list'))


@admin_bp.route('/guru/<int:id>/toggle', methods=['POST'])
@role_required('admin')
def guru_toggle(id):
    guru = validate_tenant_resource(User.query.get(id))
    guru.is_active = not guru.is_active
    db.session.commit()
    status = 'diaktifkan' if guru.is_active else 'dinonaktifkan'
    flash(f'Guru {guru.name} telah {status}.', 'success')
    return redirect(url_for('admin.guru_list'))


# ==================== MURID CRUD ====================

@admin_bp.route('/murid')
@role_required('admin')
def murid_list():
    murid = tenant_query(User).filter_by(role='murid').order_by(User.name).all()
    return render_template('admin/murid_list.html', murid_list=murid)


@admin_bp.route('/murid/tambah', methods=['GET', 'POST'])
@role_required('admin')
def murid_add():
    kelas_list = tenant_query(Kelas).order_by(Kelas.name).all()
    if request.method == 'POST':
        email = request.form['email']
        if User.query.filter_by(email=email).first():
            flash('Email sudah digunakan.', 'error')
            return render_template('admin/murid_form.html', edit=False, kelas_list=kelas_list)
        murid = User(
            school_id=g.school_id,
            name=request.form['name'],
            email=email,
            role='murid'
        )
        murid.set_password(request.form['password'])
        db.session.add(murid)
        db.session.flush()

        kelas_id = request.form.get('kelas_id')
        if kelas_id:
            kelas = validate_tenant_resource(Kelas.query.get(int(kelas_id)))
            enrollment = KelasMurid(school_id=g.school_id, kelas_id=kelas.id, murid_id=murid.id)
            db.session.add(enrollment)

        db.session.commit()
        flash('Murid berhasil ditambahkan.', 'success')
        return redirect(url_for('admin.murid_list'))
    return render_template('admin/murid_form.html', edit=False, kelas_list=kelas_list)


@admin_bp.route('/murid/<int:id>/edit', methods=['GET', 'POST'])
@role_required('admin')
def murid_edit(id):
    murid = validate_tenant_resource(User.query.get(id))
    kelas_list = tenant_query(Kelas).order_by(Kelas.name).all()
    current_enrollment = KelasMurid.query.filter_by(murid_id=murid.id).first()
    if request.method == 'POST':
        email = request.form['email']
        existing = User.query.filter_by(email=email).first()
        if existing and existing.id != murid.id:
            flash('Email sudah digunakan.', 'error')
            return render_template('admin/murid_form.html', edit=True, murid=murid, kelas_list=kelas_list, current_enrollment=current_enrollment)
        murid.name = request.form['name']
        murid.email = email
        if request.form.get('password'):
            murid.set_password(request.form['password'])

        kelas_id = request.form.get('kelas_id')
        if current_enrollment:
            if kelas_id:
                validate_tenant_resource(Kelas.query.get(int(kelas_id)))
                current_enrollment.kelas_id = int(kelas_id)
            else:
                db.session.delete(current_enrollment)
        elif kelas_id:
            validate_tenant_resource(Kelas.query.get(int(kelas_id)))
            enrollment = KelasMurid(school_id=g.school_id, kelas_id=int(kelas_id), murid_id=murid.id)
            db.session.add(enrollment)

        db.session.commit()
        flash('Data murid berhasil diperbarui.', 'success')
        return redirect(url_for('admin.murid_list'))
    return render_template('admin/murid_form.html', edit=True, murid=murid, kelas_list=kelas_list, current_enrollment=current_enrollment)


@admin_bp.route('/murid/<int:id>/delete', methods=['POST'])
@role_required('admin')
def murid_delete(id):
    murid = validate_tenant_resource(User.query.get(id))
    KelasMurid.query.filter_by(murid_id=murid.id).delete()
    db.session.delete(murid)
    db.session.commit()
    flash('Murid berhasil dihapus.', 'success')
    return redirect(url_for('admin.murid_list'))


# ==================== MURID BULK IMPORT ====================

@admin_bp.route('/murid/bulk', methods=['GET', 'POST'])
@role_required('admin')
def murid_bulk():
    kelas_list = tenant_query(Kelas).order_by(Kelas.name).all()
    kelas_map = {k.name.lower(): k for k in kelas_list}
    # Also map by name without spaces for flexibility
    kelas_map_normalized = {}
    for k in kelas_list:
        normalized = k.name.lower().replace(' ', '').replace('-', '')
        kelas_map_normalized[normalized] = k

    preview = None
    if request.method == 'POST':
        action = request.form.get('action', 'import')

        if action == 'import':
            preview_data = request.form.get('preview_data')
            if not preview_data:
                flash('Silakan lakukan preview terlebih dahulu sebelum import.', 'error')
                return redirect(url_for('admin.murid_bulk'))

            import json
            try:
                data = json.loads(preview_data)
            except Exception:
                flash('Data preview tidak valid.', 'error')
                return redirect(url_for('admin.murid_bulk'))

            created = 0
            skipped = 0
            errors = []
            for item in data:
                name = item.get('name', '').strip()
                kelas_name = item.get('kelas', '').strip()
                if not name:
                    continue

                # Generate email from name
                base_email = _generate_email(name, g.school_id)
                if not base_email:
                    skipped += 1
                    errors.append(f'{name}: format nama tidak valid')
                    continue

                # Check if email already exists
                existing = User.query.filter_by(email=base_email).first()
                if existing:
                    skipped += 1
                    errors.append(f'{name}: email sudah digunakan ({base_email})')
                    continue

                # Create user
                murid = User(
                    school_id=g.school_id,
                    name=name,
                    email=base_email,
                    role='murid'
                )
                murid.set_password('passwd')
                db.session.add(murid)
                db.session.flush()

                # Enroll to kelas if matched
                kelas_id = item.get('kelas_id')
                if kelas_id:
                    kelas = validate_tenant_resource(Kelas.query.get(int(kelas_id)))
                    if kelas:
                        enrollment = KelasMurid(
                            school_id=g.school_id,
                            kelas_id=kelas.id,
                            murid_id=murid.id
                        )
                        db.session.add(enrollment)

                created += 1

            db.session.commit()

            msg = f'Bulk import selesai: {created} murid berhasil dibuat'
            if skipped:
                msg += f', {skipped} dilewati'
            if errors:
                msg += f'. Error: {"; ".join(errors[:5])}'
            flash(msg, 'success' if created > 0 else 'warning')
            return redirect(url_for('admin.murid_list'))

        # Preview action
        raw_text = request.form.get('bulk_text', '').strip()
        if not raw_text:
            flash('Silakan masukkan data murid terlebih dahulu.', 'error')
            return render_template('admin/murid_bulk.html', kelas_list=kelas_list, preview=None)

        preview = _parse_bulk_murid(raw_text, kelas_map, kelas_map_normalized, g.school_id)
        return render_template('admin/murid_bulk.html', kelas_list=kelas_list, preview=preview)

    return render_template('admin/murid_bulk.html', kelas_list=kelas_list, preview=None)


def _parse_bulk_murid(raw_text, kelas_map, kelas_map_normalized, school_id):
    """Parse bulk text into structured data with kelas matching."""
    import json
    lines = [line.strip() for line in raw_text.split('\n') if line.strip()]

    results = []
    for line in lines:
        # Skip header-like lines
        if line.lower().startswith('nama') and ('kelas' in line.lower()):
            continue

        name = ''
        kelas_name = ''
        kelas_id = None

        # Try tab-separated first, then comma, then try to extract
        if '\t' in line:
            parts = line.split('\t')
            name = parts[0].strip()
            kelas_name = parts[1].strip() if len(parts) > 1 else ''
        elif ',' in line:
            parts = line.split(',', 1)
            name = parts[0].strip()
            kelas_name = parts[1].strip() if len(parts) > 1 else ''
        else:
            # Single name only, no kelas
            name = line.strip()
            kelas_name = ''

        if not name:
            continue

        # Match kelas
        matched_kelas = None
        if kelas_name:
            # Direct match (case insensitive)
            matched_kelas = kelas_map.get(kelas_name.lower())
            # Normalized match (without spaces/dashes)
            if not matched_kelas:
                normalized = kelas_name.lower().replace(' ', '').replace('-', '')
                matched_kelas = kelas_map_normalized.get(normalized)
            # Partial match
            if not matched_kelas:
                for key, k in kelas_map.items():
                    if key in kelas_name.lower() or kelas_name.lower() in key:
                        matched_kelas = k
                        break

            if matched_kelas:
                kelas_id = matched_kelas.id
                kelas_name = matched_kelas.name

        results.append({
            'name': name,
            'kelas': kelas_name,
            'kelas_id': kelas_id,
        })

    return {
        'students': results,
        'total': len(results),
        'matched_kelas': sum(1 for s in results if s['kelas_id']),
        'unmatched_kelas': sum(1 for s in results if s['kelas'] and not s['kelas_id']),
        'json': json.dumps(results),
    }


def _generate_email(name, school_id):
    """Generate a unique email from a student name."""
    import re
    # Clean name: lowercase, replace spaces and special chars with dots
    cleaned = re.sub(r'[^a-zA-Z0-9\s]', '', name).lower()
    cleaned = re.sub(r'\s+', '.', cleaned)
    # Remove consecutive dots
    cleaned = re.sub(r'\.{2,}', '.', cleaned).strip('.')

    if not cleaned:
        return None

    base = f'murid.{cleaned}@school{school_id}.iqrapath.local'

    # Check uniqueness, add number if needed
    email = base
    counter = 1
    while User.query.filter_by(email=email).first():
        email = f'murid.{cleaned}.{counter}@school{school_id}.iqrapath.local'
        counter += 1

    return email


# ==================== KELAS CRUD ====================

@admin_bp.route('/kelas')
@role_required('admin')
def kelas_list():
    kelas = tenant_query(Kelas).order_by(Kelas.name).all()
    return render_template('admin/kelas_list.html', kelas_list=kelas)


@admin_bp.route('/kelas/tambah', methods=['GET', 'POST'])
@role_required('admin')
def kelas_add():
    if request.method == 'POST':
        kelas = Kelas(
            school_id=g.school_id,
            name=request.form['name'],
            academic_year=request.form['academic_year']
        )
        db.session.add(kelas)
        db.session.commit()
        flash('Kelas berhasil ditambahkan.', 'success')
        return redirect(url_for('admin.kelas_list'))
    return render_template('admin/kelas_form.html', edit=False)


@admin_bp.route('/kelas/<int:id>/edit', methods=['GET', 'POST'])
@role_required('admin')
def kelas_edit(id):
    kelas = validate_tenant_resource(Kelas.query.get(id))
    if request.method == 'POST':
        kelas.name = request.form['name']
        kelas.academic_year = request.form['academic_year']
        db.session.commit()
        flash('Data kelas berhasil diperbarui.', 'success')
        return redirect(url_for('admin.kelas_list'))
    return render_template('admin/kelas_form.html', edit=True, kelas=kelas)


@admin_bp.route('/kelas/<int:id>/delete', methods=['POST'])
@role_required('admin')
def kelas_delete(id):
    kelas = validate_tenant_resource(Kelas.query.get(id))
    KelasMurid.query.filter_by(kelas_id=kelas.id).delete()
    db.session.delete(kelas)
    db.session.commit()
    flash('Kelas berhasil dihapus.', 'success')
    return redirect(url_for('admin.kelas_list'))


# ==================== MATA PELAJARAN CRUD ====================

@admin_bp.route('/mapel')
@role_required('admin')
def mapel_list():
    mapel = tenant_query(MataPelajaran).order_by(MataPelajaran.name).all()
    return render_template('admin/mapel_list.html', mapel_list=mapel)


@admin_bp.route('/mapel/tambah', methods=['GET', 'POST'])
@role_required('admin')
def mapel_add():
    if request.method == 'POST':
        mapel = MataPelajaran(
            school_id=g.school_id,
            name=request.form['name'],
            description=request.form.get('description', '')
        )
        db.session.add(mapel)
        db.session.commit()
        flash('Mata pelajaran berhasil ditambahkan.', 'success')
        return redirect(url_for('admin.mapel_list'))
    return render_template('admin/mapel_form.html', edit=False)


@admin_bp.route('/mapel/<int:id>/edit', methods=['GET', 'POST'])
@role_required('admin')
def mapel_edit(id):
    mapel = validate_tenant_resource(MataPelajaran.query.get(id))
    if request.method == 'POST':
        mapel.name = request.form['name']
        mapel.description = request.form.get('description', '')
        db.session.commit()
        flash('Data mata pelajaran berhasil diperbarui.', 'success')
        return redirect(url_for('admin.mapel_list'))
    return render_template('admin/mapel_form.html', edit=True, mapel=mapel)


@admin_bp.route('/mapel/<int:id>/delete', methods=['POST'])
@role_required('admin')
def mapel_delete(id):
    mapel = validate_tenant_resource(MataPelajaran.query.get(id))
    db.session.delete(mapel)
    db.session.commit()
    flash('Mata pelajaran berhasil dihapus.', 'success')
    return redirect(url_for('admin.mapel_list'))


# ==================== JADWAL CRUD ====================

@admin_bp.route('/jadwal')
@role_required('admin')
def jadwal_list():
    jadwal = tenant_query(Jadwal).order_by(Jadwal.day, Jadwal.start_time).all()
    return render_template('admin/jadwal_list.html', jadwal_list=jadwal)


@admin_bp.route('/jadwal/tambah', methods=['GET', 'POST'])
@role_required('admin')
def jadwal_add():
    kelas_list = tenant_query(Kelas).order_by(Kelas.name).all()
    guru_list = tenant_query(User).filter_by(role='guru').order_by(User.name).all()
    mapel_list = tenant_query(MataPelajaran).order_by(MataPelajaran.name).all()
    if request.method == 'POST':
        validate_tenant_resource(Kelas.query.get(int(request.form['kelas_id'])))
        validate_tenant_resource(User.query.get(int(request.form['guru_id'])))
        validate_tenant_resource(MataPelajaran.query.get(int(request.form['mapel_id'])))
        jadwal = Jadwal(
            school_id=g.school_id,
            kelas_id=int(request.form['kelas_id']),
            guru_id=int(request.form['guru_id']),
            mata_pelajaran_id=int(request.form['mapel_id']),
            day=request.form['day'],
            start_time=time.fromisoformat(request.form['start_time']),
            end_time=time.fromisoformat(request.form['end_time'])
        )
        db.session.add(jadwal)
        db.session.commit()
        flash('Jadwal berhasil ditambahkan.', 'success')
        return redirect(url_for('admin.jadwal_list'))
    return render_template('admin/jadwal_form.html', edit=False, kelas_list=kelas_list, guru_list=guru_list, mapel_list=mapel_list)


@admin_bp.route('/jadwal/<int:id>/edit', methods=['GET', 'POST'])
@role_required('admin')
def jadwal_edit(id):
    jadwal = validate_tenant_resource(Jadwal.query.get(id))
    kelas_list = tenant_query(Kelas).order_by(Kelas.name).all()
    guru_list = tenant_query(User).filter_by(role='guru').order_by(User.name).all()
    mapel_list = tenant_query(MataPelajaran).order_by(MataPelajaran.name).all()
    if request.method == 'POST':
        validate_tenant_resource(Kelas.query.get(int(request.form['kelas_id'])))
        validate_tenant_resource(User.query.get(int(request.form['guru_id'])))
        validate_tenant_resource(MataPelajaran.query.get(int(request.form['mapel_id'])))
        jadwal.kelas_id = int(request.form['kelas_id'])
        jadwal.guru_id = int(request.form['guru_id'])
        jadwal.mata_pelajaran_id = int(request.form['mapel_id'])
        jadwal.day = request.form['day']
        jadwal.start_time = time.fromisoformat(request.form['start_time'])
        jadwal.end_time = time.fromisoformat(request.form['end_time'])
        db.session.commit()
        flash('Jadwal berhasil diperbarui.', 'success')
        return redirect(url_for('admin.jadwal_list'))
    return render_template('admin/jadwal_form.html', edit=True, jadwal=jadwal, kelas_list=kelas_list, guru_list=guru_list, mapel_list=mapel_list)


@admin_bp.route('/jadwal/<int:id>/delete', methods=['POST'])
@role_required('admin')
def jadwal_delete(id):
    jadwal = validate_tenant_resource(Jadwal.query.get(id))
    db.session.delete(jadwal)
    db.session.commit()
    flash('Jadwal berhasil dihapus.', 'success')
    return redirect(url_for('admin.jadwal_list'))
