#!/bin/bash
# ================================================================
# OKRFEDEF — Sprint 10: Dashboard Junta Directiva
# Vistas ejecutivas, aprobación digital, informe JD
# Ejecutar desde: /home/evolucionamos/public_html/estrategia
# Comando: bash sprint_10_junta.sh
# ================================================================
set -e
echo "========================================="
echo "  OKRFEDEF — Sprint 10: Junta Directiva"
echo "========================================="

php artisan make:controller BoardController
php artisan make:job BoardReportJob

echo ">>> Archivos base creados. Escribiendo lógica..."

# ── 1. BOARD CONTROLLER ──────────────────────────────────────────
cat > app/Http/Controllers/BoardController.php << 'PHP'
<?php
namespace App\Http\Controllers;

use App\Jobs\BoardReportJob;
use App\Models\AiMessage;
use App\Models\Cycle;
use App\Models\Project;
use App\Services\ClaudeService;
use App\Services\OkrService;
use Barryvdh\DomPDF\Facade\Pdf;
use Illuminate\Http\Request;
use Inertia\Inertia;

class BoardController extends Controller
{
    public function __construct(
        private OkrService    $okr,
        private ClaudeService $claude
    ) {}

    /**
     * Dashboard ejecutivo para la Junta Directiva
     */
    public function dashboard(Project $project, Cycle $cycle)
    {
        // Solo nivel institucional para la JD
        $fullTree = $this->okr->buildOkrTree($cycle);
        $tree     = collect($fullTree)->where('level', 'institutional')->values();
        $summary  = $this->okr->getCycleScoreSummary($cycle);

        // Apuestas activas
        $bets = $project->strategicBets()->where('status', 'active')->get();

        // Renuncias formalizadas
        $renunciations = \App\Models\Renunciation::where('project_id', $project->id)
            ->where('formalized', true)->get();

        // Último análisis mensual
        $latestMonthly = AiMessage::where('project_id', $project->id)
            ->where('module', 'monthly')->latest()->first();

        // Ciclos históricos para tendencia
        $historicalCycles = Cycle::where('project_id', $project->id)
            ->orderBy('year')->orderBy('quarter')
            ->get()
            ->map(fn($c) => [
                'label'   => "Q{$c->quarter} {$c->year}",
                'quarter' => $c->quarter,
                'year'    => $c->year,
                'status'  => $c->status,
            ]);

        return Inertia::render('Board/Dashboard', [
            'project'         => $project->load('organization'),
            'cycle'           => $cycle,
            'tree'            => $tree,
            'summary'         => $summary,
            'bets'            => $bets,
            'renunciations'   => $renunciations,
            'latestMonthly'   => $latestMonthly?->response,
            'historicalCycles'=> $historicalCycles,
        ]);
    }

    /**
     * Chat IA para la Junta (solo consultas ejecutivas)
     */
    public function boardChat(Request $request, Project $project, Cycle $cycle)
    {
        $request->validate(['question' => 'required|string|max:500']);

        $summary = $this->okr->getCycleScoreSummary($cycle);
        $context = "Rol: Miembro de Junta Directiva\nScore del plan: " . round($summary['score'] * 100) . "%\n";
        $context .= "Verdes: {$summary['green']} | Amarillos: {$summary['yellow']} | Rojos: {$summary['red']}";

        $response = $this->claude->liveChat($project, $request->question, ['board_context' => $context]);

        $message = $this->claude->saveMessage(
            $project->id, 'board', $request->question, $response, 'consultive'
        );

        return response()->json([
            'response'   => $response,
            'message_id' => $message->id,
        ]);
    }

    /**
     * Aprobación formal del plan por la JD
     */
    public function approve(Request $request, Project $project)
    {
        $request->validate([
            'approver_name' => 'required|string',
            'comments'      => 'nullable|string|max:500',
        ]);

        // Guardar aprobación como mensaje IA tipo board
        AiMessage::create([
            'project_id' => $project->id,
            'user_id'    => auth()->id(),
            'module'     => 'board',
            'context'    => [
                'type'           => 'approval',
                'approver_name'  => $request->approver_name,
                'approved_at'    => now()->toISOString(),
                'comments'       => $request->comments,
            ],
            'prompt'     => 'Aprobación formal del plan estratégico',
            'response'   => "Plan estratégico aprobado por {$request->approver_name} el " . now()->format('d/m/Y H:i'),
            'model'      => 'manual',
            'trigger'    => 'consultive',
        ]);

        $project->update(['status' => 'active']);

        return response()->json(['message' => 'Plan aprobado exitosamente.']);
    }

    /**
     * Exportar informe ejecutivo PDF para la JD
     */
    public function exportPdf(Project $project, Cycle $cycle)
    {
        $tree    = collect($this->okr->buildOkrTree($cycle))->where('level', 'institutional')->values();
        $summary = $this->okr->getCycleScoreSummary($cycle);
        $bets    = $project->strategicBets()->where('status', 'active')->get();

        $latestMonthly = AiMessage::where('project_id', $project->id)
            ->where('module', 'monthly')->latest()->first();

        $pdf = Pdf::loadView('pdf.board_report', [
            'project'      => $project->load('organization'),
            'cycle'        => $cycle,
            'tree'         => $tree,
            'summary'      => $summary,
            'bets'         => $bets,
            'analysis'     => $latestMonthly?->response,
            'generated_at' => now()->format('d/m/Y H:i'),
        ]);

        return $pdf->download("Informe_Ejecutivo_Q{$cycle->quarter}_{$cycle->year}.pdf");
    }
}
PHP

# ── 2. BOARD REPORT JOB ──────────────────────────────────────────
cat > app/Jobs/BoardReportJob.php << 'PHP'
<?php
namespace App\Jobs;

use App\Events\AiResponseReady;
use App\Models\AiMessage;
use App\Models\Cycle;
use App\Models\Project;
use App\Services\ClaudeService;
use App\Services\OkrService;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;

class BoardReportJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public int $tries = 3;
    public int $timeout = 120;

    public function __construct(
        public Project $project,
        public Cycle   $cycle
    ) {}

    public function handle(ClaudeService $claude, OkrService $okr): void
    {
        $summary    = $okr->getCycleScoreSummary($this->cycle);
        $objectives = $this->cycle->objectives()->with('keyResults')->get();
        $bets       = $this->project->strategicBets()->where('status','active')->get();

        $objText = $objectives->map(fn($o) =>
            "- {$o->title}: " . round($o->score * 100) . "%"
        )->join("\n");

        $betsText = $bets->map(fn($b) =>
            "- {$b->hypothesis} (score: {$b->score})"
        )->join("\n") ?: 'Sin apuestas activas';

        $prompt = <<<PROMPT
Genera el informe ejecutivo mensual para la Junta Directiva de {$this->project->organization->name}.

PERÍODO: Q{$this->cycle->quarter} {$this->cycle->year}
SCORE GENERAL: {$summary['score']}%
OBJETIVOS EN VERDE: {$summary['green']} | AMARILLO: {$summary['yellow']} | ROJO: {$summary['red']}

OBJETIVOS:
{$objText}

APUESTAS ESTRATÉGICAS:
{$betsText}

Genera un informe ejecutivo conciso para la Junta con este formato:

**INFORME EJECUTIVO — Q{$this->cycle->quarter} {$this->cycle->year}**

**RESUMEN PARA LA JUNTA** (2 párrafos de 2-3 oraciones cada uno)
[Estado del plan y lo más importante que la JD debe saber]

**SEMÁFORO ESTRATÉGICO**
🟢 Objetivos en verde: [lista breve]
🟡 Objetivos en amarillo: [lista con causa principal]
🔴 Objetivos en rojo: [lista con acción requerida de la JD si aplica]

**APUESTAS ESTRATÉGICAS** (estado de cada una en una línea)

**DECISIONES QUE REQUIEREN LA JUNTA**
[Solo si hay algo que requiere acción o decisión de la JD. Si no hay nada, escribir "Ninguna en este período."]

**INDICADOR DE CONFIANZA**: [ALTO / MEDIO / BAJO] — [Frase de justificación]

Tono: ejecutivo, directo, sin tecnicismos de metodología OKR. Máximo 300 palabras.
PROMPT;

        $response = $claude->ask($prompt, $claude->buildSystemPrompt($this->project), 1000);

        if ($response) {
            $message = AiMessage::create([
                'project_id'  => $this->project->id,
                'module'      => 'board',
                'context'     => ['type' => 'monthly_report', 'cycle_id' => $this->cycle->id],
                'prompt'      => $prompt,
                'response'    => $response,
                'model'       => config('services.anthropic.model'),
                'trigger'     => 'proactive',
            ]);

            broadcast(new AiResponseReady($this->project->id, 'board', $response, $message->id));
        }
    }
}
PHP

# ── 3. PLANTILLA PDF JD ──────────────────────────────────────────
cat > resources/views/pdf/board_report.blade.php << 'BLADE'
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <style>
        body { font-family: Arial, sans-serif; font-size: 12px; color: #333; margin: 0; }
        .header { background: #1B5E20; color: white; padding: 20px 30px; margin-bottom: 25px; }
        .header h1 { font-size: 22px; margin: 0 0 5px 0; }
        .header p { margin: 0; opacity: 0.85; font-size: 12px; }
        .section { margin: 0 30px 20px 30px; }
        h2 { color: #1B5E20; font-size: 14px; border-bottom: 1px solid #C8E6C9; padding-bottom: 4px; }
        .grid { display: table; width: 100%; margin-bottom: 15px; }
        .col { display: table-cell; padding: 10px; border-radius: 6px; text-align: center; }
        .score-box { background: #E8F5E9; }
        .green-box { background: #E8F5E9; }
        .yellow-box { background: #FFFDE7; }
        .red-box { background: #FFEBEE; }
        .big-num { font-size: 28px; font-weight: bold; }
        .label { font-size: 10px; color: #666; margin-top: 3px; }
        .obj-row { padding: 6px 0; border-bottom: 1px solid #f0f0f0; display: flex; justify-content: space-between; }
        .bet-row { padding: 5px 0; font-style: italic; color: #555; }
        .analysis { background: #F9F9F9; padding: 12px; border-radius: 6px; white-space: pre-line; font-size: 11px; line-height: 1.5; }
        .footer { margin-top: 30px; padding: 15px 30px; background: #F5F5F5; font-size: 10px; color: #888; }
    </style>
</head>
<body>
    <div class="header">
        <h1>INFORME EJECUTIVO — Junta Directiva</h1>
        <p>{{ $project->organization->name }} · {{ $project->name }} · Q{{ $cycle->quarter }} {{ $cycle->year }}</p>
        <p style="margin-top:5px">Generado: {{ $generated_at }}</p>
    </div>

    <div class="section">
        <h2>Semáforo Estratégico</h2>
        <div class="grid">
            <div class="col score-box">
                <div class="big-num" style="color: {{ $summary['score'] >= 0.70 ? '#2E7D32' : ($summary['score'] >= 0.40 ? '#F57F17' : '#C62828') }}">
                    {{ round($summary['score'] * 100) }}%
                </div>
                <div class="label">Score general</div>
            </div>
            <div class="col green-box" style="margin-left:8px">
                <div class="big-num" style="color:#2E7D32">{{ $summary['green'] }}</div>
                <div class="label">🟢 En verde</div>
            </div>
            <div class="col yellow-box" style="margin-left:8px">
                <div class="big-num" style="color:#F57F17">{{ $summary['yellow'] }}</div>
                <div class="label">🟡 En amarillo</div>
            </div>
            <div class="col red-box" style="margin-left:8px">
                <div class="big-num" style="color:#C62828">{{ $summary['red'] }}</div>
                <div class="label">🔴 En rojo</div>
            </div>
        </div>
    </div>

    <div class="section">
        <h2>Objetivos Institucionales</h2>
        @foreach($tree as $obj)
        <div class="obj-row">
            <span>{{ $obj['title'] }}</span>
            <strong style="color: {{ $obj['score'] >= 0.70 ? '#2E7D32' : ($obj['score'] >= 0.40 ? '#F57F17' : '#C62828') }}">
                {{ round($obj['score'] * 100) }}%
            </strong>
        </div>
        @endforeach
    </div>

    @if($bets->count())
    <div class="section">
        <h2>Apuestas Estratégicas Activas</h2>
        @foreach($bets as $bet)
        <div class="bet-row">• {{ $bet->hypothesis }} (score: {{ $bet->score }}/5)</div>
        @endforeach
    </div>
    @endif

    @if($analysis)
    <div class="section">
        <h2>Análisis Ejecutivo (Claude AI)</h2>
        <div class="analysis">{{ $analysis }}</div>
    </div>
    @endif

    <div class="footer">
        {{ $project->organization->name }} · Plataforma OKRFEDEF · estrategia.evolucionamos.com · Metodología OKR + Estrategia Emergente
    </div>
</body>
</html>
BLADE

# ── 4. RUTAS ─────────────────────────────────────────────────────
cat >> routes/web.php << 'PHP'

// ── Board / Junta Directiva Routes ───────────────────────────────
use App\Http\Controllers\BoardController;

Route::middleware(['auth', 'verified'])->prefix('projects/{project}')->group(function () {
    Route::get('/cycles/{cycle}/board',          [BoardController::class, 'dashboard'])->name('board.dashboard');
    Route::post('/cycles/{cycle}/board/chat',    [BoardController::class, 'boardChat'])->name('board.chat');
    Route::post('/board/approve',                [BoardController::class, 'approve'])->name('board.approve');
    Route::get('/cycles/{cycle}/board/pdf',      [BoardController::class, 'exportPdf'])->name('board.pdf');
});
PHP

# ── 5. VISTA DASHBOARD JD ────────────────────────────────────────
mkdir -p resources/js/Pages/Board

cat > resources/js/Pages/Board/Dashboard.vue << 'VUE'
<script setup>
import { ref } from 'vue'
import AppLayout from '@/Layouts/AppLayout.vue'
import axios from 'axios'

const props = defineProps({
    project: Object,
    cycle: Object,
    tree: Array,
    summary: Object,
    bets: Array,
    renunciations: Array,
    latestMonthly: String,
    historicalCycles: Array,
})

const question = ref('')
const chatMessages = ref([])
const asking = ref(false)

const ask = async () => {
    if (!question.value.trim() || asking.value) return
    const q = question.value
    question.value = ''
    asking.value = true
    chatMessages.value.push({ role: 'user', text: q })

    try {
        const res = await axios.post(route('board.chat', [props.project.id, props.cycle.id]), { question: q })
        chatMessages.value.push({ role: 'ai', text: res.data.response })
    } catch { chatMessages.value.push({ role: 'error', text: 'Error al consultar.' }) }
    finally { asking.value = false }
}

const scoreBar = (s) => Math.round(s * 100)
const scoreColor = (s) => s >= 0.70 ? 'text-green-600' : s >= 0.40 ? 'text-yellow-600' : 'text-red-600'
const tlBg = (tl) => tl === 'green' ? 'bg-green-500' : tl === 'yellow' ? 'bg-yellow-500' : 'bg-red-500'
</script>

<template>
    <AppLayout :title="`Junta Directiva — ${project.name}`">
        <div class="max-w-5xl mx-auto px-4 py-8">

            <div class="mb-8">
                <p class="text-sm text-gray-400">{{ project.organization?.name }}</p>
                <h1 class="text-3xl font-black text-gray-900">Plan Estratégico</h1>
                <p class="text-gray-500 mt-1">Q{{ cycle.quarter }} {{ cycle.year }} · Solo lectura — Junta Directiva</p>
            </div>

            <!-- Score principal -->
            <div class="bg-gradient-to-br from-gray-900 to-gray-800 text-white rounded-3xl p-8 mb-6 text-center">
                <div class="text-7xl font-black mb-2" :class="scoreColor(summary.score)">
                    {{ scoreBar(summary.score) }}%
                </div>
                <p class="text-gray-400">avance general del plan estratégico</p>
                <div class="flex justify-center gap-8 mt-4">
                    <div class="text-center"><span class="text-3xl font-black text-green-400">{{ summary.green }}</span><div class="text-xs text-gray-400">verde</div></div>
                    <div class="text-center"><span class="text-3xl font-black text-yellow-400">{{ summary.yellow }}</span><div class="text-xs text-gray-400">amarillo</div></div>
                    <div class="text-center"><span class="text-3xl font-black text-red-400">{{ summary.red }}</span><div class="text-xs text-gray-400">rojo</div></div>
                </div>
            </div>

            <div class="grid grid-cols-3 gap-6">
                <div class="col-span-2 space-y-4">

                    <!-- Objetivos institucionales -->
                    <div class="space-y-3">
                        <div v-for="obj in tree" :key="obj.id"
                             :class="['rounded-2xl shadow p-5 border-l-4',
                                 obj.score >= 0.70 ? 'border-green-500 bg-green-50' :
                                 obj.score >= 0.40 ? 'border-yellow-500 bg-yellow-50' : 'border-red-500 bg-red-50']">
                            <div class="flex justify-between items-center mb-3">
                                <h2 class="text-lg font-bold text-gray-800 flex-1 pr-4">{{ obj.title }}</h2>
                                <div class="text-3xl font-black shrink-0" :class="scoreColor(obj.score)">
                                    {{ scoreBar(obj.score) }}%
                                </div>
                            </div>
                            <div class="w-full bg-white bg-opacity-60 rounded-full h-2">
                                <div :class="['h-2 rounded-full', tlBg(obj.score >= 0.70 ? 'green' : obj.score >= 0.40 ? 'yellow' : 'red')]"
                                     :style="`width: ${scoreBar(obj.score)}%`">
                                </div>
                            </div>
                            <p class="text-xs text-gray-500 mt-2">{{ obj.key_results?.length }} indicadores clave</p>
                        </div>
                    </div>

                    <!-- Apuestas estratégicas -->
                    <div v-if="bets.length" class="bg-white rounded-2xl shadow p-5">
                        <h2 class="text-sm font-semibold text-gray-600 uppercase mb-3">Apuestas Estratégicas Activas</h2>
                        <div v-for="bet in bets" :key="bet.id" class="mb-3 p-3 bg-blue-50 rounded-xl">
                            <p class="text-sm font-medium text-gray-800">{{ bet.hypothesis }}</p>
                            <div class="flex gap-4 mt-1 text-xs text-gray-500">
                                <span>Viabilidad: {{ bet.feasibility_avg }}/5</span>
                                <span>Impacto: {{ bet.impact_avg }}/5</span>
                                <span class="font-bold text-blue-700">Score: {{ bet.score }}/5</span>
                            </div>
                        </div>
                    </div>

                    <!-- Renuncias formalizadas -->
                    <div v-if="renunciations.length" class="bg-white rounded-2xl shadow p-5">
                        <h2 class="text-sm font-semibold text-gray-600 uppercase mb-3">Renuncias Estratégicas Formalizadas</h2>
                        <div v-for="r in renunciations" :key="r.id"
                             class="mb-2 p-3 bg-red-50 rounded-xl border-l-4 border-red-400">
                            <p class="text-sm text-gray-700">{{ r.description }}</p>
                            <span class="text-xs text-red-600 font-medium">{{ r.approval_rate }}% aprobación</span>
                        </div>
                    </div>

                    <!-- Análisis mensual -->
                    <div v-if="latestMonthly" class="bg-gray-900 text-white rounded-2xl p-5">
                        <div class="flex items-center gap-2 mb-3">
                            <div class="w-6 h-6 bg-purple-600 rounded-full flex items-center justify-center text-white text-xs font-bold">C</div>
                            <span class="font-semibold text-sm">Análisis ejecutivo — Claude AI</span>
                        </div>
                        <div class="text-gray-300 text-sm whitespace-pre-line leading-relaxed">{{ latestMonthly }}</div>
                    </div>
                </div>

                <!-- Panel lateral: chat JD -->
                <div>
                    <div class="bg-white rounded-2xl shadow p-4 mb-4">
                        <h2 class="text-sm font-semibold text-gray-700 mb-3">Consultar al sistema</h2>
                        <div class="bg-gray-50 rounded-xl p-3 h-48 overflow-y-auto mb-3 space-y-2">
                            <div v-if="!chatMessages.length" class="text-center text-gray-400 text-xs mt-8">
                                Haz una pregunta sobre el plan
                            </div>
                            <div v-for="(m, i) in chatMessages" :key="i">
                                <div v-if="m.role === 'user'" class="text-right">
                                    <span class="bg-blue-600 text-white text-xs rounded-xl px-3 py-1.5 inline-block">{{ m.text }}</span>
                                </div>
                                <div v-else-if="m.role === 'ai'" class="text-xs text-gray-700 bg-white rounded-xl p-2 border">{{ m.text }}</div>
                                <div v-else class="text-xs text-red-400">{{ m.text }}</div>
                            </div>
                            <div v-if="asking" class="flex gap-1 p-2">
                                <div class="w-1.5 h-1.5 bg-gray-400 rounded-full animate-bounce"></div>
                                <div class="w-1.5 h-1.5 bg-gray-400 rounded-full animate-bounce delay-75"></div>
                                <div class="w-1.5 h-1.5 bg-gray-400 rounded-full animate-bounce delay-150"></div>
                            </div>
                        </div>
                        <div class="flex gap-2">
                            <input v-model="question" @keydown.enter="ask"
                                   placeholder="¿Cómo va el crédito?"
                                   class="flex-1 border border-gray-300 rounded-lg px-3 py-1.5 text-xs focus:ring-1 focus:ring-blue-500" />
                            <button @click="ask" :disabled="asking || !question.trim()"
                                    class="bg-blue-600 text-white px-3 py-1.5 rounded-lg text-xs disabled:bg-gray-300">→</button>
                        </div>
                    </div>

                    <!-- Exportar PDF -->
                    <a :href="route('board.pdf', [project.id, cycle.id])"
                       class="block w-full bg-gray-800 text-white text-center py-3 rounded-xl text-sm font-medium hover:bg-gray-700 transition-colors">
                        ↓ Exportar informe PDF
                    </a>
                </div>
            </div>
        </div>
    </AppLayout>
</template>
VUE

# ── 6. COMPILAR Y CACHEAR ────────────────────────────────────────
echo ">>> Compilando assets Vue..."
npm run build

php artisan config:clear
php artisan route:clear
php artisan config:cache
php artisan route:cache
php artisan view:cache

echo ""
echo "========================================="
echo "  Sprint 10 completado exitosamente"
echo ""
echo "  ✅ BoardController (dashboard, chat,"
echo "     aprobación, exportPDF)"
echo "  ✅ BoardReportJob (informe ejecutivo IA)"
echo "  ✅ Plantilla PDF informe JD"
echo "  ✅ Vista Board/Dashboard.vue"
echo "     (solo nivel institucional, chat JD)"
echo ""
echo "  Ruta: /projects/{id}/cycles/{c}/board"
echo "========================================="
