<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use App\Models\{
    Stabile,
    MovimentoBancario,
    TransazioneContabile,
    RiconciliazioneBancaria,
    ContoCorrente
};

/**
 * ========================================
 * CONTROLLER RICONCILIAZIONE BANCARIA
 * Sistema avanzato matching automatico/manuale
 * ========================================
 */
class RiconciliazioniController extends Controller
{
    /**
     * Dashboard riconciliazioni
     */
    public function index()
    {
        $amministratore_id = Auth::user()->amministratore->id_amministratore ?? null;
        
        // Statistiche
        $stats = [
            'movimenti_non_riconciliati' => MovimentoBancario::whereHas('contoCorrente.stabile', function($q) use ($amministratore_id) {
                $q->where('amministratore_id', $amministratore_id);
            })->where('riconciliato', false)->count(),
            
            'differenze_trovate' => RiconciliazioneBancaria::whereHas('contoCorrente.stabile', function($q) use ($amministratore_id) {
                $q->where('amministratore_id', $amministratore_id);
            })->where('stato', 'con_differenze')->count(),
            
            'importo_non_riconciliato' => MovimentoBancario::whereHas('contoCorrente.stabile', function($q) use ($amministratore_id) {
                $q->where('amministratore_id', $amministratore_id);
            })->where('riconciliato', false)->sum('importo'),
        ];

        // Conti correnti attivi
        $contiCorrenti = ContoCorrente::whereHas('stabile', function($q) use ($amministratore_id) {
            $q->where('amministratore_id', $amministratore_id);
        })->with('stabile')->get();

        // Ultime riconciliazioni
        $ultimeRiconciliazioni = RiconciliazioneBancaria::whereHas('contoCorrente.stabile', function($q) use ($amministratore_id) {
            $q->where('amministratore_id', $amministratore_id);
        })->with(['contoCorrente.stabile', 'utente'])
          ->orderBy('data_riconciliazione', 'desc')
          ->take(10)
          ->get();

        return view('admin.riconciliazioni.index', compact(
            'stats', 'contiCorrenti', 'ultimeRiconciliazioni'
        ));
    }

    /**
     * Avvia processo di riconciliazione per un conto
     */
    public function create(Request $request)
    {
        $request->validate([
            'conto_corrente_id' => 'required|exists:conti_correnti,id',
            'data_da' => 'required|date',
            'data_a' => 'required|date|after_or_equal:data_da'
        ]);

        $conto = ContoCorrente::with('stabile')->find($request->conto_corrente_id);
        
        // Verifica autorizzazioni
        $amministratore_id = Auth::user()->amministratore->id_amministratore ?? null;
        if ($conto->stabile->amministratore_id !== $amministratore_id) {
            abort(403);
        }

        // Movimenti bancari non riconciliati nel periodo
        $movimentiBancari = MovimentoBancario::where('conto_corrente_id', $conto->id)
            ->whereBetween('data_valuta', [$request->data_da, $request->data_a])
            ->where('riconciliato', false)
            ->orderBy('data_valuta')
            ->get();

        // Transazioni contabili nel periodo
        $transazioniContabili = TransazioneContabile::where('stabile_id', $conto->stabile_id)
            ->whereBetween('data_registrazione', [$request->data_da, $request->data_a])
            ->where('riconciliata', false)
            ->whereHas('righe', function($q) {
                $q->whereHas('conto', function($q2) {
                    $q2->where('tipo_conto', 'banca');
                });
            })
            ->with(['righe.conto'])
            ->orderBy('data_registrazione')
            ->get();

        // Matching automatico preliminare
        $matchingSuggeriti = $this->eseguiMatchingAutomatico($movimentiBancari, $transazioniContabili);

        return view('admin.riconciliazioni.create', compact(
            'conto', 'movimentiBancari', 'transazioniContabili', 'matchingSuggeriti'
        ));
    }

    /**
     * Salva riconciliazione
     */
    public function store(Request $request)
    {
        $request->validate([
            'conto_corrente_id' => 'required|exists:conti_correnti,id',
            'data_da' => 'required|date',
            'data_a' => 'required|date',
            'saldo_iniziale' => 'required|numeric',
            'saldo_finale' => 'required|numeric',
            'matching' => 'required|array',
            'matching.*.movimento_bancario_id' => 'required|exists:movimenti_bancari,id',
            'matching.*.transazione_contabile_id' => 'nullable|exists:transazioni_contabili,id',
            'matching.*.tipo_matching' => 'required|in:automatico,manuale,non_trovato',
            'differenze_non_giustificate' => 'nullable|array'
        ]);

        DB::beginTransaction();
        try {
            $conto = ContoCorrente::find($request->conto_corrente_id);
            
            // Crea record riconciliazione
            $riconciliazione = RiconciliazioneBancaria::create([
                'conto_corrente_id' => $request->conto_corrente_id,
                'data_riconciliazione' => now(),
                'periodo_da' => $request->data_da,
                'periodo_a' => $request->data_a,
                'saldo_iniziale_bancario' => $request->saldo_iniziale,
                'saldo_finale_bancario' => $request->saldo_finale,
                'saldo_iniziale_contabile' => $this->calcolaSaldoContabile($conto, $request->data_da, true),
                'saldo_finale_contabile' => $this->calcolaSaldoContabile($conto, $request->data_a, false),
                'stato' => 'in_progress',
                'utente_id' => Auth::id()
            ]);

            $movimentiRiconciliati = 0;
            $importoRiconciliato = 0;
            $differenzeNonGiustificate = [];

            // Processa ogni matching
            foreach ($request->matching as $match) {
                $movimentoBancario = MovimentoBancario::find($match['movimento_bancario_id']);
                
                if ($match['tipo_matching'] === 'automatico' || $match['tipo_matching'] === 'manuale') {
                    if (isset($match['transazione_contabile_id'])) {
                        $transazione = TransazioneContabile::find($match['transazione_contabile_id']);
                        
                        // Marca come riconciliati
                        $movimentoBancario->update([
                            'riconciliato' => true,
                            'transazione_contabile_id' => $transazione->id,
                            'riconciliazione_id' => $riconciliazione->id,
                            'tipo_matching' => $match['tipo_matching']
                        ]);
                        
                        $transazione->update(['riconciliata' => true]);
                        
                        $movimentiRiconciliati++;
                        $importoRiconciliato += abs($movimentoBancario->importo);
                    }
                } else {
                    // Movimento non trovato - possibile differenza
                    $differenzeNonGiustificate[] = [
                        'movimento_bancario_id' => $movimentoBancario->id,
                        'importo' => $movimentoBancario->importo,
                        'descrizione' => $movimentoBancario->descrizione,
                        'data' => $movimentoBancario->data_valuta
                    ];
                }
            }

            // Calcola stato finale
            $stato = 'completata';
            if (count($differenzeNonGiustificate) > 0) {
                $stato = 'con_differenze';
            }

            $differenzaSaldi = abs($riconciliazione->saldo_finale_bancario - $riconciliazione->saldo_finale_contabile);
            if ($differenzaSaldi > 0.01) {
                $stato = 'con_differenze';
            }

            // Aggiorna riconciliazione
            $riconciliazione->update([
                'movimenti_riconciliati' => $movimentiRiconciliati,
                'importo_riconciliato' => $importoRiconciliato,
                'differenze_non_giustificate' => json_encode($differenzeNonGiustificate),
                'differenza_saldi' => $differenzaSaldi,
                'stato' => $stato,
                'note_riconciliazione' => $request->note ?? null
            ]);

            DB::commit();

            $message = "Riconciliazione completata. Movimenti riconciliati: {$movimentiRiconciliati}";
            if ($stato === 'con_differenze') {
                $message .= " - ATTENZIONE: Sono presenti differenze da verificare.";
            }

            return redirect()
                ->route('admin.riconciliazioni.show', $riconciliazione)
                ->with('success', $message);

        } catch (\Exception $e) {
            DB::rollback();
            return back()
                ->withInput()
                ->withErrors(['error' => 'Errore durante la riconciliazione: ' . $e->getMessage()]);
        }
    }

    /**
     * Mostra dettagli riconciliazione
     */
    public function show(RiconciliazioneBancaria $riconciliazione)
    {
        $riconciliazione->load([
            'contoCorrente.stabile',
            'movimentiBancari.transazioneContabile',
            'utente'
        ]);

        $differenzeNonGiustificate = json_decode($riconciliazione->differenze_non_giustificate, true) ?? [];

        return view('admin.riconciliazioni.show', compact(
            'riconciliazione', 'differenzeNonGiustificate'
        ));
    }

    /**
     * API: Matching automatico in tempo reale
     */
    public function matchingAutomatico(Request $request)
    {
        $request->validate([
            'movimento_bancario_id' => 'required|exists:movimenti_bancari,id',
            'conto_corrente_id' => 'required|exists:conti_correnti,id',
            'data_da' => 'required|date',
            'data_a' => 'required|date'
        ]);

        $movimentoBancario = MovimentoBancario::find($request->movimento_bancario_id);
        
        // Criteri di matching automatico
        $transazioniCandidati = TransazioneContabile::whereHas('stabile.contiCorrenti', function($q) use ($request) {
            $q->where('id', $request->conto_corrente_id);
        })
        ->whereBetween('data_registrazione', [$request->data_da, $request->data_a])
        ->where('riconciliata', false)
        ->where(function($q) use ($movimentoBancario) {
            // Matching per importo esatto
            $q->where('importo_totale', abs($movimentoBancario->importo))
              // Matching per numero documento
              ->orWhere('numero_documento', 'LIKE', '%' . $movimentoBancario->numero_operazione . '%')
              // Matching per descrizione
              ->orWhere('descrizione', 'LIKE', '%' . substr($movimentoBancario->descrizione, 0, 20) . '%');
        })
        ->with(['fornitore', 'righe.conto'])
        ->get();

        // Calcola score di matching
        $candidatiConScore = $transazioniCandidati->map(function($transazione) use ($movimentoBancario) {
            $score = 0;
            
            // Score per importo
            if (abs($transazione->importo_totale - abs($movimentoBancario->importo)) < 0.01) {
                $score += 50;
            } elseif (abs($transazione->importo_totale - abs($movimentoBancario->importo)) < 10) {
                $score += 20;
            }
            
            // Score per data
            $diffGiorni = abs($transazione->data_registrazione->diffInDays($movimentoBancario->data_valuta));
            if ($diffGiorni <= 1) {
                $score += 30;
            } elseif ($diffGiorni <= 7) {
                $score += 15;
            }
            
            // Score per descrizione
            if (stripos($movimentoBancario->descrizione, $transazione->numero_documento) !== false) {
                $score += 25;
            }
            
            if ($transazione->fornitore && stripos($movimentoBancario->descrizione, $transazione->fornitore->ragione_sociale) !== false) {
                $score += 20;
            }

            $transazione->matching_score = $score;
            return $transazione;
        })->sortByDesc('matching_score');

        return response()->json([
            'candidati' => $candidatiConScore->take(5)->values(),
            'movimento_bancario' => $movimentoBancario
        ]);
    }

    /**
     * Esegue matching automatico preliminare
     */
    private function eseguiMatchingAutomatico($movimentiBancari, $transazioniContabili)
    {
        $matching = [];
        
        foreach ($movimentiBancari as $movimento) {
            $miglioreMatch = null;
            $migliorScore = 0;
            
            foreach ($transazioniContabili as $transazione) {
                $score = 0;
                
                // Matching per importo esatto
                if (abs($transazione->importo_totale - abs($movimento->importo)) < 0.01) {
                    $score += 60;
                }
                
                // Matching per data (più vicine = score più alto)
                $diffGiorni = abs($transazione->data_registrazione->diffInDays($movimento->data_valuta));
                if ($diffGiorni <= 1) {
                    $score += 30;
                } elseif ($diffGiorni <= 3) {
                    $score += 15;
                }
                
                // Matching per numero documento
                if ($transazione->numero_documento && stripos($movimento->descrizione, $transazione->numero_documento) !== false) {
                    $score += 20;
                }
                
                if ($score > $migliorScore && $score >= 70) { // Soglia minima per matching automatico
                    $migliorScore = $score;
                    $miglioreMatch = $transazione;
                }
            }
            
            $matching[] = [
                'movimento_bancario' => $movimento,
                'transazione_suggerita' => $miglioreMatch,
                'score' => $migliorScore,
                'tipo_suggerimento' => $migliorScore >= 80 ? 'automatico' : 'manuale'
            ];
        }
        
        return $matching;
    }

    /**
     * Calcola saldo contabile alla data
     */
    private function calcolaSaldoContabile($conto, $data, $iniziale = false)
    {
        // Implementazione calcolo saldo contabile dal piano dei conti
        // Basato sulle transazioni registrate fino alla data specificata
        return 0; // Placeholder
    }
}
