from flask import Blueprint, render_template, request, redirect, url_for, flash
import config
from db import get_db
from services.filters import range_start, parse_statuses, now_iso
from services.refresh_flows import refresh_flows
from services.upload import save_flow_file, delete_flow_file
from routes.dashboard import _aggregate
from routes.flows import _flow_run_counts
import requests

bp = Blueprint('pages', __name__)

RANGE_OPTIONS = [
    ('15m', '15 دقیقه گذشته'),
    ('30m', '30 دقیقه گذشته'),
    ('1h', '1 ساعت گذشته'),
    ('24h', '24 ساعت گذشته'),
    ('7d', '7 روز گذشته'),
    ('30d', '30 روز گذشته'),
]
STATUSES = config.RUN_STATUSES


def _row_to_flow_dict(row):
    return {
        'id': row['id'],
        'name': row['name'],
        'description': row['description'],
        'servicesInfo': row['servicesInfo'],
        'isActive': bool(row['isActive']),
        'file': (
            {'originalName': row['fileOriginalName'], 'mimeType': row['fileMimeType']}
            if row['fileOriginalName']
            else None
        ),
        'fileStoredName': row['fileStoredName'],
    }


def _fetch_runs(conn, flow_id, range_key, statuses):
    since = range_start(range_key)
    query = 'SELECT Run.*, Flow.name as flowName FROM Run JOIN Flow ON Run.flowId = Flow.id WHERE 1=1'
    params = []
    if flow_id:
        query += ' AND Run.flowId = ?'
        params.append(flow_id)
    if since:
        query += ' AND Run.startedAt >= ?'
        params.append(since)
    if statuses:
        placeholders = ','.join('?' for _ in statuses)
        query += f' AND Run.status IN ({placeholders})'
        params.extend(statuses)
    query += ' ORDER BY Run.startedAt DESC LIMIT 500'
    return conn.execute(query, params).fetchall()


@bp.route('/')
def index():
    conn = get_db()
    try:
        sections = [
            ('Last 24 hours', _aggregate(conn, range_start('24h'))),
            ('Last 7 days', _aggregate(conn, range_start('7d'))),
            ('Last 30 days', _aggregate(conn, range_start('30d'))),
            ('All time', _aggregate(conn, None)),
        ]
    finally:
        conn.close()
    return render_template('dashboard.html', sections=sections, generated_at=now_iso())


@bp.route('/flows')
def flows_list():
    conn = get_db()
    try:
        rows = conn.execute('SELECT * FROM Flow ORDER BY name ASC').fetchall()
        flows = []
        for row in rows:
            flows.append(
                {
                    'id': row['id'],
                    'name': row['name'],
                    'ranges': {
                        '24h': _flow_run_counts(conn, row['id'], range_start('24h')),
                        '7d': _flow_run_counts(conn, row['id'], range_start('7d')),
                        '30d': _flow_run_counts(conn, row['id'], range_start('30d')),
                    },
                }
            )
    finally:
        conn.close()

    refresh_message = request.args.get('msg')
    refresh_ok = request.args.get('ok') == '1'
    return render_template('flows.html', flows=flows, refresh_message=refresh_message, refresh_ok=refresh_ok)


@bp.route('/flows/refresh', methods=['POST'])
def refresh_flows_action():
    try:
        result = refresh_flows()
        return redirect(url_for('pages.flows_list', ok='1', msg=f"{result['synced']} flow synced"))
    except Exception as err:
        return redirect(url_for('pages.flows_list', ok='0', msg=str(err)))


@bp.route('/flows/<flow_id>')
def flow_detail(flow_id):
    conn = get_db()
    try:
        row = conn.execute('SELECT * FROM Flow WHERE id = ?', (flow_id,)).fetchone()
        if not row:
            return 'Flow not found', 404
        flow = _row_to_flow_dict(row)

        range_key = request.args.get('range', '24h')
        statuses = request.args.getlist('status') or []
        runs = _fetch_runs(conn, flow_id, range_key, statuses)
    finally:
        conn.close()

    toggle_error = request.args.get('toggle_error')
    return render_template(
        'flow_detail.html',
        flow=flow,
        range_options=RANGE_OPTIONS,
        current_range=range_key,
        statuses=STATUSES,
        current_statuses=statuses,
        runs=runs,
        generated_at=now_iso(),
        toggle_error=toggle_error,
    )


@bp.route('/flows/<flow_id>/save-meta', methods=['POST'])
def save_meta_action(flow_id):
    field = request.form.get('field')
    if field not in ('description', 'servicesInfo'):
        return redirect(url_for('pages.flow_detail', flow_id=flow_id))
    value = request.form.get(field, '')

    conn = get_db()
    try:
        conn.execute(f'UPDATE Flow SET {field} = ?, updatedAt = ? WHERE id = ?', (value, now_iso(), flow_id))
        conn.commit()
    finally:
        conn.close()
    return redirect(url_for('pages.flow_detail', flow_id=flow_id))


@bp.route('/flows/<flow_id>/upload-file', methods=['POST'])
def upload_file_action(flow_id):
    conn = get_db()
    try:
        flow = conn.execute('SELECT * FROM Flow WHERE id = ?', (flow_id,)).fetchone()
        file_storage = request.files.get('file')
        if flow and file_storage and file_storage.filename:
            delete_flow_file(flow_id, flow['fileStoredName'])
            stored_name = save_flow_file(flow_id, file_storage)
            conn.execute(
                'UPDATE Flow SET fileOriginalName = ?, fileStoredName = ?, fileMimeType = ?, updatedAt = ? WHERE id = ?',
                (file_storage.filename, stored_name, file_storage.mimetype, now_iso(), flow_id),
            )
            conn.commit()
    finally:
        conn.close()
    return redirect(url_for('pages.flow_detail', flow_id=flow_id))


@bp.route('/flows/<flow_id>/delete-file', methods=['POST'])
def delete_file_action(flow_id):
    conn = get_db()
    try:
        flow = conn.execute('SELECT * FROM Flow WHERE id = ?', (flow_id,)).fetchone()
        if flow:
            delete_flow_file(flow_id, flow['fileStoredName'])
            conn.execute(
                'UPDATE Flow SET fileOriginalName = NULL, fileStoredName = NULL, fileMimeType = NULL, updatedAt = ? WHERE id = ?',
                (now_iso(), flow_id),
            )
            conn.commit()
    finally:
        conn.close()
    return redirect(url_for('pages.flow_detail', flow_id=flow_id))


@bp.route('/flows/<flow_id>/toggle-active', methods=['POST'])
def toggle_active_action(flow_id):
    conn = get_db()
    try:
        flow = conn.execute('SELECT * FROM Flow WHERE id = ?', (flow_id,)).fetchone()
        if not flow:
            return redirect(url_for('pages.flows_list'))

        if not config.WEBHOOK_FLOW_TOGGLE_URL:
            return redirect(url_for('pages.flow_detail', flow_id=flow_id, toggle_error='وبهوک تنظیم نشده است'))

        action = 'deactivate' if flow['isActive'] else 'activate'
        try:
            resp = requests.post(
                config.WEBHOOK_FLOW_TOGGLE_URL, json={'flowId': flow_id, 'action': action}, timeout=15
            )
            resp.raise_for_status()
        except Exception:
            return redirect(url_for('pages.flow_detail', flow_id=flow_id, toggle_error='ارسال به وبهوک ناموفق بود'))

        new_active = 0 if flow['isActive'] else 1
        conn.execute('UPDATE Flow SET isActive = ?, updatedAt = ? WHERE id = ?', (new_active, now_iso(), flow_id))
        conn.commit()
    finally:
        conn.close()
    return redirect(url_for('pages.flow_detail', flow_id=flow_id))


@bp.route('/reports')
def reports():
    conn = get_db()
    try:
        range_key = request.args.get('range', '24h')
        statuses = request.args.getlist('status') or []
        runs = _fetch_runs(conn, None, range_key, statuses)
    finally:
        conn.close()

    return render_template(
        'reports.html',
        range_options=RANGE_OPTIONS,
        current_range=range_key,
        statuses=STATUSES,
        current_statuses=statuses,
        runs=runs,
        generated_at=now_iso(),
    )


@bp.route('/fetch-log', methods=['GET', 'POST'])
def fetch_log():
    execution_id = None
    entries = None
    raw_result = None
    error = None

    if request.method == 'POST':
        execution_id = (request.form.get('executionId') or '').strip()
        if execution_id and config.WEBHOOK_LOG_URL:
            try:
                resp = requests.post(config.WEBHOOK_LOG_URL, json={'executionId': execution_id}, timeout=15)
                resp.raise_for_status()
                result = resp.json()
                if isinstance(result, list):
                    entries = result
                else:
                    raw_result = result
            except Exception:
                error = 'Failed to fetch log for this execution ID.'
        elif not config.WEBHOOK_LOG_URL:
            error = 'WEBHOOK_LOG_URL is not configured'

    return render_template(
        'fetch_log.html', execution_id=execution_id, entries=entries, raw_result=raw_result, error=error
    )
