#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
SUCESU API Client — Python com Flask

Aplicação Flask que funciona como proxy/interface para a API de Unidades
Regionais do SUCESU. Cada rota Flask representa uma operação da API.

Requisitos:
    pip install flask requests

Uso:
    export SUCESU_API_TOKEN="asc_SEU_TOKEN"
    export FLASK_APP=sucusu_client.py
    flask run

    # Ou execute diretamente:
    python sucusu_client.py

Testes (sem servidor):
    python sucusu_client.py --test

Documentação da API:
    wiki/api/unidade-regional.md
"""

import os
import json
import sys
import requests
from flask import Flask, request as flask_request, jsonify

# ─── Configuração ──────────────────────────────────────────────

API_BASE  = os.environ.get('SUCESU_API_BASE', 'https://seu-dominio.com/api/v2/unidaderegional')
API_TOKEN = os.environ.get('SUCESU_API_TOKEN', 'asc_SEU_TOKEN_AQUI')

app = Flask(__name__)


# ─── Classe SucesuClient ───────────────────────────────────────

class SucesuClient:
    """
    Cliente Python para a API SUCESU.

    Encapsula todas as 6 operações (CRUD notícias + associados)
    com tratamento de erros padronizado.

    Uso::

        client = SucesuClient('asc_SEU_TOKEN')
        resultado = client.criar_noticia({'title': 'Olá', 'content': '...'})

        if resultado['ok']:
            print(resultado['data'])
    """

    def __init__(self, token, base_url=None):
        """
        Inicializa o cliente.

        Args:
            token (str): Bearer token da regional
            base_url (str, optional): URL base da API
        """
        self.token = token
        self.base_url = base_url or API_BASE
        self.session = requests.Session()
        self.session.headers.update({
            'Authorization': f'Bearer {self.token}',
            'Content-Type':  'application/json',
            'Accept':        'application/json',
        })
        self.session.timeout = 30

    def _request(self, method, path, data=None):
        """
        Envia uma requisição HTTP.

        Args:
            method (str): Método HTTP (GET, POST, DELETE)
            path (str): Caminho relativo (ex: '/noticias')
            data (dict, optional): Dados para envio

        Returns:
            dict: {'ok': bool, 'status': int, 'body': dict}
        """
        url = f'{self.base_url}{path}'

        try:
            if method == 'GET':
                response = self.session.get(url)
            elif method == 'POST':
                response = self.session.post(url, json=data)
            elif method == 'DELETE':
                response = self.session.delete(url)
            else:
                return {'ok': False, 'status': 0, 'body': {'error': {'detail': f'Método {method} não suportado'}}}

            try:
                body = response.json()
            except ValueError:
                body = {'raw': response.text}

            return {
                'ok':     response.ok,
                'status': response.status_code,
                'body':   body,
            }

        except requests.exceptions.ConnectionError as e:
            return {'ok': False, 'status': 0, 'body': {'error': {'title': 'Connection Error', 'detail': str(e)}}}
        except requests.exceptions.Timeout as e:
            return {'ok': False, 'status': 0, 'body': {'error': {'title': 'Timeout', 'detail': str(e)}}}
        except requests.exceptions.RequestException as e:
            return {'ok': False, 'status': 0, 'body': {'error': {'title': 'Request Error', 'detail': str(e)}}}

    # ── Notícias ──

    def criar_noticia(self, campos):
        """
        Cria uma nova notícia.

        Args:
            campos (dict): {'title': str, 'content': str, 'subtitle'?: str, 'tags'?: list}

        Returns:
            dict: Resultado padronizado da API
        """
        return self._request('POST', '/noticias', campos)

    def listar_noticias(self, por_pagina=15):
        """
        Lista notícias da regional autenticada.

        Args:
            por_pagina (int): Itens por página (padrão: 15)

        Returns:
            dict: Resultado padronizado da API
        """
        return self._request('GET', f'/noticias?per_page={por_pagina}')

    def atualizar_noticia(self, noticia_id, campos):
        """
        Atualiza uma notícia existente (atualização parcial).

        Args:
            noticia_id (str): UUID da notícia
            campos (dict): Campos a atualizar

        Returns:
            dict: Resultado padronizado da API
        """
        return self._request('POST', f'/noticias/{noticia_id}', campos)

    def arquivar_noticia(self, noticia_id):
        """
        Arquiva (soft-delete) uma notícia.

        Args:
            noticia_id (str): UUID da notícia

        Returns:
            dict: Resultado padronizado da API
        """
        return self._request('DELETE', f'/noticias/{noticia_id}')

    # ── Associados ──

    def criar_associado(self, campos):
        """
        Cria um novo associado (description em Markdown).

        Args:
            campos (dict): {'name': str, 'description'?: str, 'tags'?: str}

        Returns:
            dict: Resultado padronizado da API
        """
        return self._request('POST', '/associados', campos)

    def vincular_associados(self, ids, status=None, tags=None):
        """
        Vincula associados existentes à regional.

        Args:
            ids (list): Lista de UUIDs dos associados
            status (str, optional): 'active' ou 'inactive'
            tags (str, optional): Tags separadas por vírgula

        Returns:
            dict: Resultado padronizado da API
        """
        data = {'empresa_ids': ids}
        if status is not None:
            data['status'] = status
        if tags is not None:
            data['tags'] = tags
        return self._request('POST', '/associados', data)

    def atualizar_associado(self, associado_id, campos):
        """
        Atualiza um associado existente (atualização parcial).

        Args:
            associado_id (str): UUID do AssociadoInstituicao
            campos (dict): Campos a atualizar

        Returns:
            dict: Resultado padronizado da API
        """
        return self._request('POST', f'/associados/{associado_id}', campos)

    def listar_associados(self):
        """
        Lista associados vinculados à regional autenticada.

        Returns:
            dict: Resultado padronizado da API
        """
        return self._request('GET', '/associados')

    def arquivar_associado(self, vinculo_id):
        """
        Arquiva (soft-delete) um associado e seu vínculo.

        Args:
            vinculo_id (str): UUID do vínculo (UnidadeRegionalEmpresa)

        Returns:
            dict: Resultado padronizado da API
        """
        return self._request('DELETE', f'/associados/{vinculo_id}')


# ─── Rotas Flask (Interface Web) ───────────────────────────────

client = SucesuClient(API_TOKEN)


@app.route('/')
def index():
    """Página inicial — lista operações disponíveis."""
    return jsonify({
        'service': 'SUCESU API Client — Python/Flask',
        'base_url': API_BASE,
        'endpoints': {
            'GET  /noticias':         'Listar notícias',
            'POST /noticias':         'Criar notícia (JSON body)',
            'POST /noticias/update':  'Atualizar notícia (JSON com id)',
            'DELETE /noticias/<id>':  'Arquivar notícia',
            'GET  /associados':       'Listar associados',
            'POST /associados':       'Criar associado (JSON body)',
            'POST /associados/link':  'Vincular existentes (JSON com empresa_ids)',
            'POST /associados/update':'Atualizar associado (JSON com id)',
            'DELETE /associados/<id>':'Arquivar associado',
        },
    })


@app.route('/noticias', methods=['GET'])
def get_noticias():
    """Lista notícias da regional autenticada."""
    per_page = flask_request.args.get('per_page', 15, type=int)
    resultado = client.listar_noticias(per_page)
    return jsonify(resultado['body']), resultado['status']


@app.route('/noticias', methods=['POST'])
def post_noticias():
    """Cria uma nova notícia."""
    data = flask_request.get_json(force=True)
    resultado = client.criar_noticia(data)
    return jsonify(resultado['body']), resultado['status']


@app.route('/noticias/update', methods=['POST'])
def update_noticia():
    """Atualiza uma notícia existente."""
    data = flask_request.get_json(force=True)
    if 'id' not in data:
        return jsonify({'ok': False, 'message': 'Campo "id" é obrigatório'}), 422
    noticia_id = data.pop('id')
    resultado = client.atualizar_noticia(noticia_id, data)
    return jsonify(resultado['body']), resultado['status']


@app.route('/noticias/<noticia_id>', methods=['DELETE'])
def delete_noticia(noticia_id):
    """Arquiva uma notícia."""
    resultado = client.arquivar_noticia(noticia_id)
    return jsonify(resultado['body']), resultado['status']


@app.route('/associados', methods=['GET'])
def get_associados():
    """Lista associados vinculados à regional."""
    resultado = client.listar_associados()
    return jsonify(resultado['body']), resultado['status']


@app.route('/associados', methods=['POST'])
def post_associados():
    """Cria um novo associado."""
    data = flask_request.get_json(force=True)
    resultado = client.criar_associado(data)
    return jsonify(resultado['body']), resultado['status']


@app.route('/associados/link', methods=['POST'])
def link_associados():
    """Vincula associados existentes."""
    data = flask_request.get_json(force=True)
    if 'empresa_ids' not in data:
        return jsonify({'ok': False, 'message': 'Campo "empresa_ids" é obrigatório'}), 422
    resultado = client.vincular_associados(
        data['empresa_ids'],
        data.get('status'),
        data.get('tags'),
    )
    return jsonify(resultado['body']), resultado['status']


@app.route('/associados/update', methods=['POST'])
def update_associado():
    """Atualiza um associado existente."""
    data = flask_request.get_json(force=True)
    if 'id' not in data:
        return jsonify({'ok': False, 'message': 'Campo "id" é obrigatório'}), 422
    associado_id = data.pop('id')
    resultado = client.atualizar_associado(associado_id, data)
    return jsonify(resultado['body']), resultado['status']


@app.route('/associados/<vinculo_id>', methods=['DELETE'])
def delete_associado(vinculo_id):
    """Arquiva um associado."""
    resultado = client.arquivar_associado(vinculo_id)
    return jsonify(resultado['body']), resultado['status']


# ─── Modo Teste (sem servidor) ─────────────────────────────────

def run_tests():
    """Executa testes automatizados de todas as operações."""
    print('╔══════════════════════════════════════════════════════════╗')
    print('║  SUCESU API Client — Testes Python                    ║')
    print('╚══════════════════════════════════════════════════════════╝')
    print(f'\n  Base URL: {API_BASE}')

    results = []

    # 1. Criar notícia
    print('\n' + '─' * 60)
    print('  1. Criar Notícia')
    r = client.criar_noticia({
        'title': 'Exemplo via Python/Flask',
        'content': '## Resumo\n\nCriada via requests em Python.\n\n- Item 1\n- Item 2',
        'tags': ['exemplo', 'python'],
    })
    noticia_id = r['body'].get('data', {}).get('id')
    results.append(('Criar Notícia', r['ok'], r['status']))
    print(f"  HTTP {r['status']} — {'OK' if r['ok'] else 'FALHOU'}")

    # 2. Listar notícias
    print('\n' + '─' * 60)
    print('  2. Listar Notícias')
    r = client.listar_noticias(5)
    results.append(('Listar Notícias', r['ok'], r['status']))
    print(f"  HTTP {r['status']} — {'OK' if r['ok'] else 'FALHOU'}")

    # 3. Atualizar notícia
    if noticia_id:
        print('\n' + '─' * 60)
        print('  3. Atualizar Notícia')
        r = client.atualizar_noticia(noticia_id, {'title': 'Título Atualizado Python'})
        results.append(('Atualizar Notícia', r['ok'], r['status']))
        print(f"  HTTP {r['status']} — {'OK' if r['ok'] else 'FALHOU'}")

    # 4. Criar associado
    print('\n' + '─' * 60)
    print('  4. Criar Associado')
    r = client.criar_associado({
        'name': 'Associado Exemplo Python',
        'description': '## Convênio\n\nDesconto de **10%** para sócios.',
        'tags': 'exemplo, python',
    })
    empresa_id = r['body'].get('data', {}).get('results', [{}])[0].get('empresa_id')
    results.append(('Criar Associado', r['ok'], r['status']))
    print(f"  HTTP {r['status']} — {'OK' if r['ok'] else 'FALHOU'}")

    # 5. Listar associados
    print('\n' + '─' * 60)
    print('  5. Listar Associados')
    r = client.listar_associados()
    results.append(('Listar Associados', r['ok'], r['status']))
    print(f"  HTTP {r['status']} — {'OK' if r['ok'] else 'FALHOU'}")

    # 6. Atualizar associado
    if empresa_id:
        print('\n' + '─' * 60)
        print('  6. Atualizar Associado')
        r = client.atualizar_associado(empresa_id, {'name': 'Associado Atualizado Python'})
        results.append(('Atualizar Associado', r['ok'], r['status']))
        print(f"  HTTP {r['status']} — {'OK' if r['ok'] else 'FALHOU'}")

    # 7. Arquivar notícia
    if noticia_id:
        print('\n' + '─' * 60)
        print('  7. Arquivar Notícia')
        r = client.arquivar_noticia(noticia_id)
        results.append(('Arquivar Notícia', r['ok'], r['status']))
        print(f"  HTTP {r['status']} — {'OK' if r['ok'] else 'FALHOU'}")

    # 8. Arquivar associado
    associados = r2_body.get('data', {}).get('associados', []) if 'r2_body' in dir() else []
    if not associados and 'r' in dir():
        associados = client.listar_associados()['body'].get('data', {}).get('associados', [])
    vinculo_id = associados[0]['id'] if associados else None
    if vinculo_id:
        print('\n' + '─' * 60)
        print('  8. Arquivar Associado')
        r = client.arquivar_associado(vinculo_id)
        results.append(('Arquivar Associado', r['ok'], r['status']))
        print(f"  HTTP {r['status']} — {'OK' if r['ok'] else 'FALHOU'}")

    # Resumo
    print('\n' + '═' * 60)
    passed = sum(1 for _, ok, _ in results if ok)
    total  = len(results)
    print(f'  Resultado: {passed}/{total} operações bem-sucedidas')
    for name, ok, status in results:
        icon = '✓' if ok else '✗'
        print(f'    {icon} {name} (HTTP {status})')
    print('═' * 60 + '\n')

    return 0 if passed == total else 1


# ─── Entry Point ───────────────────────────────────────────────

if __name__ == '__main__':
    if '--test' in sys.argv:
        sys.exit(run_tests())
    else:
        print(f'SUCESU API Client — Flask em http://localhost:5000')
        print(f'Base URL: {API_BASE}')
        app.run(debug=True, port=5000)
