<?php

declare(strict_types=1);

namespace App\Controllers;

use App\Core\Controller;
use App\Core\Request;
use App\Core\Session;
use App\Models\Stock;
use App\Services\StockService;
use Throwable;

final class StockController extends Controller
{

    public function dashboard(): void
    {
        $stockModel = new Stock();
        (new StockService($stockModel))->initialize();

        $valuationRows = $stockModel->valuationRows();
        $lowStock = $stockModel->lowStockArticles();

        $this->view('stock/dashboard', [
            'title' => 'Tableau de bord stock',
            'summary' => $stockModel->summary(),
            'valuation' => $stockModel->valuationSummary(),
            'lowStock' => array_slice($lowStock, 0, 10),
            'ruptures' => array_slice(array_values(array_filter($lowStock, static fn ($row) => ($row['etat_stock'] ?? '') === 'rupture')), 0, 10),
            'topValue' => array_slice($valuationRows, 0, 10),
            'recentMovements' => $stockModel->recentMovements(10),
            'movementSummary' => $stockModel->movementSummary(['date_debut' => date('Y-m-d', strtotime('-30 days'))]),
        ]);
    }

    public function finalisation(): void
    {
        $stockModel = new Stock();
        (new StockService($stockModel))->initialize();

        $lowStock = $stockModel->lowStockArticles();

        $this->view('stock/finalisation', [
            'title' => 'Finalisation stock avancé',
            'summary' => $stockModel->summary(),
            'valuation' => $stockModel->valuationSummary(),
            'movementSummary' => $stockModel->movementSummary(['date_debut' => date('Y-m-d', strtotime('-30 days'))]),
            'lowStock' => array_slice($lowStock, 0, 8),
            'recentMovements' => $stockModel->recentMovements(8),
        ]);
    }

    public function index(): void
    {
        $stockModel = new Stock();
        (new StockService($stockModel))->initialize();

        $this->view('stock/index', [
            'title' => 'Stock',
            'stocks' => $stockModel->all(),
            'summary' => $stockModel->summary(),
        ]);
    }

    public function show(): void
    {
        $articleId = (int) Request::get('id', 0);
        $stockModel = new Stock();
        $article = $stockModel->findArticle($articleId);

        if (!$article) {
            Session::flash('error', 'Article introuvable.');
            $this->redirect('stock');
        }

        $this->view('stock/show', [
            'title' => 'Fiche stock',
            'article' => $article,
            'movements' => $stockModel->movements($articleId),
        ]);
    }


    public function history(): void
    {
        $stockModel = new Stock();
        $filters = [
            'article' => trim((string) Request::get('article', '')),
            'type' => trim((string) Request::get('type', '')),
            'date_debut' => trim((string) Request::get('date_debut', '')),
            'date_fin' => trim((string) Request::get('date_fin', '')),
            'origine' => trim((string) Request::get('origine', '')),
            'sens' => trim((string) Request::get('sens', '')),
        ];

        $this->view('stock/history', [
            'title' => 'Historique stock avancé',
            'movements' => $stockModel->allMovements($filters, 1000),
            'summary' => $stockModel->movementSummary($filters),
            'filters' => $filters,
            'types' => $stockModel->movementTypes(),
            'origins' => $stockModel->movementOrigins(),
        ]);
    }

    public function entry(): void
    {
        $stockModel = new Stock();
        $this->view('stock/entry', [
            'title' => 'Entrée de stock',
            'articles' => $stockModel->articlesForSelect(),
        ]);
    }

    public function storeEntry(): void
    {
        try {
            (new StockService())->entree(
                (int) Request::post('article_id', 0),
                $this->number(Request::post('quantite', 0)),
                $this->number(Request::post('prix_achat_ht', 0)),
                trim((string) Request::post('commentaire', ''))
            );
            Session::flash('success', 'Entrée de stock enregistrée.');
            $this->redirect('stock');
        } catch (Throwable $exception) {
            Session::flash('error', $exception->getMessage());
            $this->redirect('stock_entry');
        }
    }

    public function adjust(): void
    {
        $stockModel = new Stock();
        (new StockService($stockModel))->initialize();
        $selectedArticleId = (int) Request::get('id', Request::get('article_id', 0));

        $this->view('stock/adjust', [
            'title' => 'Ajustement manuel de stock',
            'articles' => $stockModel->articlesForAdjust(),
            'selectedArticleId' => $selectedArticleId,
        ]);
    }

    public function storeAdjust(): void
    {
        try {
            $difference = (new StockService())->ajustement(
                (int) Request::post('article_id', 0),
                $this->number(Request::post('stock_reel', 0)),
                trim((string) Request::post('commentaire', ''))
            );
            Session::flash('success', 'Ajustement manuel enregistré. Écart : ' . number_format($difference, 2, ',', ' '));
            $this->redirect('stock');
        } catch (Throwable $exception) {
            Session::flash('error', $exception->getMessage());
            $this->redirect('stock_adjust');
        }
    }



    public function alerts(): void
    {
        $stockModel = new Stock();
        (new StockService($stockModel))->initialize();

        $this->view('stock/alerts', [
            'title' => 'Stock minimum / alertes',
            'summary' => $stockModel->summary(),
            'alerts' => $stockModel->lowStockArticles(),
            'articles' => $stockModel->articlesForAdjust(),
            'selectedArticleId' => (int) Request::get('id', Request::get('article_id', 0)),
        ]);
    }

    public function storeMinimum(): void
    {
        try {
            (new StockService())->setMinimum(
                (int) Request::post('article_id', 0),
                $this->number(Request::post('stock_minimum', 0))
            );
            Session::flash('success', 'Stock minimum mis à jour.');
            $this->redirect('stock_alerts');
        } catch (Throwable $exception) {
            Session::flash('error', $exception->getMessage());
            $this->redirect('stock_alerts');
        }
    }


    public function valuation(): void
    {
        $stockModel = new Stock();
        (new StockService($stockModel))->initialize();

        $this->view('stock/valuation', [
            'title' => 'Valorisation du stock',
            'summary' => $stockModel->valuationSummary(),
            'rows' => $stockModel->valuationRows(),
        ]);
    }

    public function inventory(): void
    {
        $stockModel = new Stock();
        (new StockService($stockModel))->initialize();

        $this->view('stock/inventory', [
            'title' => 'Inventaire stock',
            'rows' => $stockModel->inventoryRows(),
            'inventories' => $stockModel->inventories(10),
        ]);
    }

    public function storeInventory(): void
    {
        try {
            $stockReel = Request::post('stock_reel', []);
            if (!is_array($stockReel)) {
                $stockReel = [];
            }

            $count = (new StockService())->inventaireGlobal(
                $stockReel,
                trim((string) Request::post('commentaire', ''))
            );

            Session::flash('success', 'Inventaire validé. ' . $count . ' ajustement(s) enregistré(s).');
            $this->redirect('stock_inventory');
        } catch (Throwable $exception) {
            Session::flash('error', $exception->getMessage());
            $this->redirect('stock_inventory');
        }
    }

    public function inventoryShow(): void
    {
        $id = (int) Request::get('id', 0);
        $stockModel = new Stock();
        $inventory = $stockModel->inventoryWithLines($id);

        if (!$inventory) {
            Session::flash('error', 'Inventaire introuvable.');
            $this->redirect('stock_inventory');
        }

        $this->view('stock/inventory_show', [
            'title' => 'Détail inventaire',
            'inventory' => $inventory,
            'lines' => $inventory['lignes'] ?? [],
        ]);
    }

    private function number(mixed $value): float
    {
        if (is_int($value) || is_float($value)) {
            return (float) $value;
        }
        $value = str_replace(["\xc2\xa0", ' ', ','], ['', '', '.'], (string) $value);
        return is_numeric($value) ? (float) $value : 0.0;
    }
}
