import requests
from flask import Blueprint, jsonify, request, send_file, abort
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, flow_file_path, delete_flow_file

bp = Blueprint('flows', __name__, url_prefix='/api/flows')


def _flow_run_counts(conn, flow_id, since_iso):
    rows = conn.execute(
        'SELECT status, COUNT(*) as cnt FROM Run WHERE flowId = ? AND startedAt >= ? GROUP BY status',
        (flow_id, since_iso),
    ).fetchall()
    counts = {'success': 0, 'failed': 0, 'running': 0, 'pending': 0}
    for row in rows:
        if row['status'] in counts:
            counts[row['status']] = row['cnt']
    total = sum(counts.values())
    return {'total': total, **counts}


@bp.route('/refresh', methods=['POST'])
def refresh():
    try:
        result = refresh_flows()
        return jsonify({'success': True, 'synced': result['synced'], 'refreshedAt': now_iso()})
    except Exception as err:
        print(f'[POST /api/flows/refresh] {err}')
        return jsonify({'success': False, 'error': str(err)}), 502


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


@bp.route('/<flow_id>')
def get_flow(flow_id):
    conn = get_db()
    try:
        flow = conn.execute('SELECT * FROM Flow WHERE id = ?', (flow_id,)).fetchone()
        if not flow:
            return jsonify({'error': 'Flow not found'}), 404
        return jsonify(
            {
                'id': flow['id'],
                'name': flow['name'],
                'description': flow['description'],
                'servicesInfo': flow['servicesInfo'],
                'isActive': bool(flow['isActive']),
                'file': (
                    {'originalName': flow['fileOriginalName'], 'mimeType': flow['fileMimeType']}
                    if flow['fileOriginalName']
                    else None
                ),
            }
        )
    finally:
        conn.close()


@bp.route('/<flow_id>', methods=['PATCH'])
def update_flow(flow_id):
    conn = get_db()
    try:
        flow = conn.execute('SELECT * FROM Flow WHERE id = ?', (flow_id,)).fetchone()
        if not flow:
            return jsonify({'error': 'Flow not found'}), 404

        body = request.get_json(silent=True) or {}
        description = body.get('description', flow['description'])
        services_info = body.get('servicesInfo', flow['servicesInfo'])

        conn.execute(
            'UPDATE Flow SET description = ?, servicesInfo = ?, updatedAt = ? WHERE id = ?',
            (description, services_info, now_iso(), flow_id),
        )
        conn.commit()
        return jsonify({'description': description, 'servicesInfo': services_info})
    finally:
        conn.close()


@bp.route('/<flow_id>/file', methods=['POST'])
def upload_file(flow_id):
    conn = get_db()
    try:
        flow = conn.execute('SELECT * FROM Flow WHERE id = ?', (flow_id,)).fetchone()
        if not flow:
            return jsonify({'error': 'Flow not found'}), 404

        file_storage = request.files.get('file')
        if not file_storage or not file_storage.filename:
            return jsonify({'error': 'file is required'}), 400

        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()
        return jsonify({'file': {'originalName': file_storage.filename, 'mimeType': file_storage.mimetype}})
    finally:
        conn.close()


@bp.route('/<flow_id>/file')
def download_file(flow_id):
    conn = get_db()
    try:
        flow = conn.execute('SELECT * FROM Flow WHERE id = ?', (flow_id,)).fetchone()
        if not flow or not flow['fileStoredName'] or not flow['fileOriginalName']:
            return jsonify({'error': 'No file uploaded for this flow'}), 404
        path = flow_file_path(flow_id, flow['fileStoredName'])
        return send_file(path, as_attachment=True, download_name=flow['fileOriginalName'])
    finally:
        conn.close()


@bp.route('/<flow_id>/file', methods=['DELETE'])
def remove_file(flow_id):
    conn = get_db()
    try:
        flow = conn.execute('SELECT * FROM Flow WHERE id = ?', (flow_id,)).fetchone()
        if not flow:
            return jsonify({'error': 'Flow not found'}), 404
        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()
        return jsonify({'success': True})
    finally:
        conn.close()


@bp.route('/<flow_id>/toggle-active', methods=['POST'])
def toggle_active(flow_id):
    conn = get_db()
    try:
        flow = conn.execute('SELECT * FROM Flow WHERE id = ?', (flow_id,)).fetchone()
        if not flow:
            return jsonify({'error': 'Flow not found'}), 404

        if not config.WEBHOOK_FLOW_TOGGLE_URL:
            return jsonify({'error': 'WEBHOOK_FLOW_TOGGLE_URL is not configured'}), 500

        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 as err:
            print(f'[POST /api/flows/{flow_id}/toggle-active] {err}')
            return jsonify({'error': 'Failed to reach the flow toggle webhook'}), 502

        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()
        return jsonify({'isActive': bool(new_active)})
    finally:
        conn.close()


@bp.route('/<flow_id>/runs')
def flow_runs(flow_id):
    conn = get_db()
    try:
        flow = conn.execute('SELECT * FROM Flow WHERE id = ?', (flow_id,)).fetchone()
        if not flow:
            return jsonify({'error': 'Flow not found'}), 404

        since = range_start(request.args.get('range'))
        statuses = parse_statuses(request.args.get('status'))

        query = 'SELECT * FROM Run WHERE flowId = ?'
        params = [flow_id]
        if since:
            query += ' AND startedAt >= ?'
            params.append(since)
        if statuses:
            placeholders = ','.join('?' for _ in statuses)
            query += f' AND status IN ({placeholders})'
            params.extend(statuses)
        query += ' ORDER BY startedAt DESC LIMIT 500'

        runs = conn.execute(query, params).fetchall()
        return jsonify(
            {
                'id': flow['id'],
                'name': flow['name'],
                'runs': [
                    {
                        'id': r['id'],
                        'flowId': r['flowId'],
                        'flowName': flow['name'],
                        'status': r['status'],
                        'startedAt': r['startedAt'],
                        'finishedAt': r['finishedAt'],
                    }
                    for r in runs
                ],
            }
        )
    finally:
        conn.close()
