from flask import Blueprint, render_template, request, redirect, url_for, flash
from flask_login import login_required, current_user
from datetime import date
from werkzeug.utils import secure_filename
import os

from models import (
    db, BroadcastMessage, BroadcastRead,
    BroadcastDepartment, BroadcastRole,
    Department, Role, Employee
)
from utils.notify import notify_many, notify_broadcast

broadcast_bp = Blueprint('broadcast', __name__)

def _annc_link(broadcast_id: int) -> str:
    return url_for('broadcast.view_announcements', _external=True) + f"#b-{broadcast_id}"

def _truncate(text: str, n=160) -> str:
    text = (text or "").strip()
    return (text[: n - 1] + "…") if len(text) > n else text

# ---------- Create/List ----------
@broadcast_bp.route('/broadcasts', methods=['GET', 'POST'])
@login_required
def manage_broadcasts():
    # ✅ Role guard always (not only when there’s an attachment)
    role_name = (getattr(getattr(current_user, "role", None), "name", "") or "").lower()
    if role_name not in {"admin", "hr", "hr admin"}:
        flash('❌ Only Admin / HR / HR Admin can manage broadcasts.', 'danger')
        return redirect(url_for('employee.dashboard'))

    ALLOWED_EXTENSIONS = {'jpg', 'jpeg', 'png', 'webp', 'pdf', 'doc', 'docx', 'xls', 'xlsx'}
    def allowed_file(fn): return '.' in fn and fn.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

    if request.method == 'POST':
        title = (request.form.get('title') or '').strip()
        content = request.form.get('content') or ''
        start_date = request.form.get('start_date') or None
        end_date   = request.form.get('end_date') or None

        # Attachment (optional)
        attachment = request.files.get('attachment')
        attachment_path = None
        if attachment and attachment.filename:
            if not allowed_file(attachment.filename):
                flash('❌ Invalid file type. Allowed: JPG, PNG, PDF, DOCX, XLSX, etc.', 'danger')
                return redirect(url_for('broadcast.manage_broadcasts'))
            filename = secure_filename(attachment.filename)
            upload_dir = os.path.join('static', 'uploads')
            os.makedirs(upload_dir, exist_ok=True)
            attachment_path = os.path.join(upload_dir, filename)
            attachment.save(attachment_path)

        # Create broadcast
        b = BroadcastMessage(
            title=title,
            content=content,
            attachment_path=attachment_path,
            start_date=start_date,
            end_date=end_date,
            created_by=current_user.id
        )
        db.session.add(b)
        db.session.flush()  # get b.id

        # ✅ Departments
        # <select name="department_ids" multiple> (may include "all")
        selected_department_ids = request.form.getlist('department_ids') or []

        if 'all' in selected_department_ids:
            # IMPORTANT: query full rows, then take .id; with_entities returns tuples
            selected_department_ids = [str(d.id) for d in Department.query.all()]

        # Cast to ints & dedupe
        dept_ids = []
        for v in selected_department_ids:
            try:
                dept_ids.append(int(v))
            except Exception:
                pass
        dept_ids = sorted(set(dept_ids))

        # Save associations
        for did in dept_ids:
            db.session.add(BroadcastDepartment(broadcast_id=b.id, department_id=did))

        db.session.commit()
        flash('✅ Broadcast message added.', 'success')

        # 🔔 Notifications
        link = _annc_link(b.id)
        title_for_bell = f"New announcement: {title}"
        msg_for_bell   = _truncate(content, 160)

        if dept_ids:
            recipients = [
                e.id for e in Employee.query
                .filter(
                    Employee.status.in_(["active", "notice"]),
                    Employee.department_id.in_(dept_ids)
                ).all()
            ]
            if recipients:
                notify_many(recipients, title_for_bell, msg_for_bell, link)
        else:
            # No department selected => org-wide
            notify_broadcast(title_for_bell, msg_for_bell, link, fanout=True)

        return redirect(url_for('broadcast.manage_broadcasts'))

    broadcasts  = BroadcastMessage.query.order_by(BroadcastMessage.created_on.desc()).all()
    departments = Department.query.order_by(Department.name).all()
    return render_template('admin/manage_broadcasts.html',
                           broadcasts=broadcasts, departments=departments)

# ---------- Delete ----------
@broadcast_bp.route('/broadcasts/delete/<int:broadcast_id>', methods=['POST'])
@login_required
def delete_broadcast(broadcast_id):
    role_name = (getattr(getattr(current_user, "role", None), "name", "") or "").lower()
    if role_name not in {"admin", "hr", "hr admin"}:
        flash('❌ Only Admin / HR / HR Admin can delete broadcasts.', 'danger')
        return redirect(url_for('employee.dashboard'))

    b = BroadcastMessage.query.get_or_404(broadcast_id)
    db.session.delete(b)
    db.session.commit()
    flash('✅ Broadcast message deleted.', 'success')
    return redirect(url_for('broadcast.manage_broadcasts'))

# ---------- Mark Read ----------
@broadcast_bp.route('/broadcasts/mark-read/<int:broadcast_id>', methods=['POST'])
@login_required
def mark_read(broadcast_id):
    already = BroadcastRead.query.filter_by(
        broadcast_id=broadcast_id, employee_id=current_user.id
    ).first()
    if not already:
        db.session.add(BroadcastRead(broadcast_id=broadcast_id, employee_id=current_user.id))
        db.session.commit()
        flash('✅ Marked as read.', 'success')
    else:
        flash('ℹ️ Already marked as read.', 'info')
    return redirect(url_for('employee.dashboard'))

# ---------- Announcements (viewer-scoped) ----------
@broadcast_bp.route('/announcements')
@login_required
def view_announcements():
    """Show only broadcasts applicable to the logged-in employee:
       - within date range
       - department-scoped (or no departments => org-wide)
       - role-scoped (if you later add roles to broadcasts)
    """
    today = date.today()
    broadcasts = (BroadcastMessage.query
        .filter(
            ((BroadcastMessage.start_date == None) | (BroadcastMessage.start_date <= today)),
            ((BroadcastMessage.end_date   == None) | (BroadcastMessage.end_date   >= today)),
            # ✅ department scope
            (~BroadcastMessage.departments.any()) |
            (BroadcastMessage.departments.any(id=current_user.department_id)),
            # ✅ role scope (kept for future—safe even if you don’t attach roles yet)
            (~BroadcastMessage.roles.any()) |
            (BroadcastMessage.roles.any(id=current_user.role_id))
        )
        .order_by(BroadcastMessage.created_on.desc())
        .all())

    return render_template('broadcast/announcements.html', broadcasts=broadcasts)