<?php

declare(strict_types=1);

namespace App\Controllers;

use App\Core\Controller;
use App\Core\Request;
use App\Core\Session;
use App\Services\ParametreSocieteService;

use App\Repositories\TypeClientRepository;
use App\Repositories\FamilleArticleRepository;
use App\Repositories\MarqueArticleRepository;
use App\Repositories\UniteArticleRepository;
use App\Repositories\TauxTvaRepository;
use App\Repositories\ModeReglementRepository;
use App\Repositories\NumerotationRepository;

use Throwable;

final class ParametreController extends Controller
{
	public function index(): void
	{
		$this->view('parametres/index', [
			'title' => 'Paramètres',
		]);
	}
	public function societe(): void
    {
        $settings = (new ParametreSocieteService())->get();

        $this->view('parametres/societe', [
            'title' => 'Paramètres société',
            'settings' => $settings,
            'errors' => [],
        ]);
    }

    public function saveSociete(): void
    {
        $service = new ParametreSocieteService();
        $data = Request::all();

        try {
            $service->save($data);
            Session::flash('success', 'Paramètres société enregistrés.');
            $this->redirect('parametres_societe');
        } catch (Throwable $exception) {
            $this->view('parametres/societe', [
                'title' => 'Paramètres société',
                'settings' => $data + $service->get(),
                'errors' => ['general' => $exception->getMessage()],
            ]);
        }
    }
	public function typesClients(): void
{
    $repository = new TypeClientRepository();

    $this->view('parametres/types_clients', [
        'title' => 'Types de clients',
        'typesClients' => $repository->all(),
    ]);
}

	public function storeTypeClient(): void
	{
		try {
			$libelle = trim((string) Request::post('libelle', ''));

			if ($libelle === '') {
				throw new \InvalidArgumentException('Le libellé est obligatoire.');
			}

			(new TypeClientRepository())->create($libelle);
			Session::flash('success', 'Type de client ajouté.');
		} catch (\Throwable $exception) {
			Session::flash('error', $exception->getMessage());
		}

		$this->redirect('parametres_types_clients');
	}

	public function updateTypeClient(): void
	{
		try {
			$id = (int) Request::post('id', 0);
			$libelle = trim((string) Request::post('libelle', ''));
			$actif = (int) Request::post('actif', 0);

			if ($id <= 0) {
				throw new \InvalidArgumentException('Type de client invalide.');
			}

			if ($libelle === '') {
				throw new \InvalidArgumentException('Le libellé est obligatoire.');
			}

			(new TypeClientRepository())->update($id, $libelle, $actif);
			Session::flash('success', 'Type de client mis à jour.');
		} catch (\Throwable $exception) {
			Session::flash('error', $exception->getMessage());
		}

		$this->redirect('parametres_types_clients');
	}

	public function deleteTypeClient(): void
	{
		try {
			$id = (int) Request::post('id', 0);

			if ($id <= 0) {
				throw new \InvalidArgumentException('Type de client invalide.');
			}

			(new TypeClientRepository())->deactivate($id);
			Session::flash('success', 'Type de client désactivé.');
		} catch (\Throwable $exception) {
			Session::flash('error', $exception->getMessage());
		}

		$this->redirect('parametres_types_clients');
	}
	public function famillesArticles(): void
	{
		$repository = new FamilleArticleRepository();

		$this->view('parametres/familles_articles', [
			'title' => 'Familles d’articles',
			'famillesArticles' => $repository->all(),
		]);
	}

	public function storeFamilleArticle(): void
	{
		try {
			$libelle = trim((string) Request::post('libelle', ''));

			if ($libelle === '') {
				throw new \InvalidArgumentException(
					'Le libellé est obligatoire.'
				);
			}

			(new FamilleArticleRepository())->create($libelle);

			Session::flash(
				'success',
				'Famille d’articles ajoutée.'
			);
		} catch (\Throwable $exception) {
			Session::flash(
				'error',
				$exception->getMessage()
			);
		}

		$this->redirect('parametres_familles_articles');
	}

	public function updateFamilleArticle(): void
	{
		try {
			$id = (int) Request::post('id', 0);
			$libelle = trim((string) Request::post('libelle', ''));
			$actif = (int) Request::post('actif', 0);

			if ($id <= 0) {
				throw new \InvalidArgumentException(
					'Famille d’articles invalide.'
				);
			}

			if ($libelle === '') {
				throw new \InvalidArgumentException(
					'Le libellé est obligatoire.'
				);
			}

			(new FamilleArticleRepository())->update(
				$id,
				$libelle,
				$actif
			);

			Session::flash(
				'success',
				'Famille d’articles mise à jour.'
			);
		} catch (\Throwable $exception) {
			Session::flash(
				'error',
				$exception->getMessage()
			);
		}

		$this->redirect('parametres_familles_articles');
	}

	public function deleteFamilleArticle(): void
	{
		try {
			$id = (int) Request::post('id', 0);

			if ($id <= 0) {
				throw new \InvalidArgumentException(
					'Famille d’articles invalide.'
				);
			}

			(new FamilleArticleRepository())->deactivate($id);

			Session::flash(
				'success',
				'Famille d’articles désactivée.'
			);
		} catch (\Throwable $exception) {
			Session::flash(
				'error',
				$exception->getMessage()
			);
		}

		$this->redirect('parametres_familles_articles');
	}
	public function marquesArticles(): void
	{
		$repository = new MarqueArticleRepository();

		$this->view('parametres/marques_articles', [
			'title' => 'Marques',
			'marquesArticles' => $repository->all(),
		]);
	}

	public function storeMarqueArticle(): void
	{
		try {
			$libelle = trim((string) Request::post('libelle', ''));

			if ($libelle === '') {
				throw new \InvalidArgumentException(
					'Le libellé est obligatoire.'
				);
			}

			(new MarqueArticleRepository())->create($libelle);

			Session::flash(
				'success',
				'Marque ajoutée.'
			);
		} catch (\Throwable $exception) {
			Session::flash(
				'error',
				$exception->getMessage()
			);
		}

		$this->redirect('parametres_marques_articles');
	}

	public function updateMarqueArticle(): void
	{
		try {
			$id = (int) Request::post('id', 0);
			$libelle = trim((string) Request::post('libelle', ''));
			$actif = (int) Request::post('actif', 0);

			if ($id <= 0) {
				throw new \InvalidArgumentException(
					'Marque invalide.'
				);
			}

			if ($libelle === '') {
				throw new \InvalidArgumentException(
					'Le libellé est obligatoire.'
				);
			}

			(new MarqueArticleRepository())->update(
				$id,
				$libelle,
				$actif
			);

			Session::flash(
				'success',
				'Marque mise à jour.'
			);
		} catch (\Throwable $exception) {
			Session::flash(
				'error',
				$exception->getMessage()
			);
		}

		$this->redirect('parametres_marques_articles');
	}

	public function deleteMarqueArticle(): void
	{
		try {
			$id = (int) Request::post('id', 0);

			if ($id <= 0) {
				throw new \InvalidArgumentException(
					'Marque invalide.'
				);
			}

			(new MarqueArticleRepository())->deactivate($id);

			Session::flash(
				'success',
				'Marque désactivée.'
			);
		} catch (\Throwable $exception) {
			Session::flash(
				'error',
				$exception->getMessage()
			);
		}

		$this->redirect('parametres_marques_articles');
	}
	public function unitesArticles(): void
	{
		$repository = new UniteArticleRepository();

		$this->view('parametres/unites_articles', [
			'title' => 'Unités',
			'unitesArticles' => $repository->all(),
		]);
	}

	public function storeUniteArticle(): void
	{
		try {
			$libelle = trim((string) Request::post('libelle', ''));

			if ($libelle === '') {
				throw new \InvalidArgumentException(
					'Le libellé est obligatoire.'
				);
			}

			(new UniteArticleRepository())->create($libelle);

			Session::flash(
				'success',
				'Unité ajoutée.'
			);
		} catch (\Throwable $exception) {
			Session::flash(
				'error',
				$exception->getMessage()
			);
		}

		$this->redirect('parametres_unites_articles');
	}

	public function updateUniteArticle(): void
	{
		try {
			$id = (int) Request::post('id', 0);
			$libelle = trim((string) Request::post('libelle', ''));
			$actif = (int) Request::post('actif', 0);

			if ($id <= 0) {
				throw new \InvalidArgumentException(
					'Unité invalide.'
				);
			}

			if ($libelle === '') {
				throw new \InvalidArgumentException(
					'Le libellé est obligatoire.'
				);
			}

			(new UniteArticleRepository())->update(
				$id,
				$libelle,
				$actif
			);

			Session::flash(
				'success',
				'Unité mise à jour.'
			);
		} catch (\Throwable $exception) {
			Session::flash(
				'error',
				$exception->getMessage()
			);
		}

		$this->redirect('parametres_unites_articles');
	}

	public function deleteUniteArticle(): void
	{
		try {
			$id = (int) Request::post('id', 0);

			if ($id <= 0) {
				throw new \InvalidArgumentException(
					'Unité invalide.'
				);
			}

			(new UniteArticleRepository())->deactivate($id);

			Session::flash(
				'success',
				'Unité désactivée.'
			);
		} catch (\Throwable $exception) {
			Session::flash(
				'error',
				$exception->getMessage()
			);
		}

		$this->redirect('parametres_unites_articles');
	}
	public function tauxTva(): void
	{
		$repository = new TauxTvaRepository();

		$this->view('parametres/taux_tva', [
			'title' => 'TVA',
			'tauxTva' => $repository->all(),
		]);
	}
	public function storeTauxTva(): void
	{
		try {

			$libelle = trim((string) Request::post('libelle', ''));
			$taux = (float) Request::post('taux', 0);
			$parDefaut = (int) Request::post('par_defaut', 0);

			if ($libelle === '') {
				throw new \InvalidArgumentException(
					'Le libellé est obligatoire.'
				);
			}

			(new TauxTvaRepository())->create(
				$libelle,
				$taux,
				$parDefaut
			);

			Session::flash(
				'success',
				'Taux de TVA ajouté.'
			);

		} catch (\Throwable $exception) {

			Session::flash(
				'error',
				$exception->getMessage()
			);
		}

		$this->redirect('parametres_taux_tva');
	}
	public function updateTauxTva(): void
	{
		try {

			$id = (int) Request::post('id');

			(new TauxTvaRepository())->update(

				$id,

				trim((string) Request::post('libelle')),

				(float) Request::post('taux'),

				(int) Request::post('par_defaut'),

				(int) Request::post('actif')

			);

			Session::flash(
				'success',
				'TVA mise à jour.'
			);

		} catch (\Throwable $exception) {

			Session::flash(
				'error',
				$exception->getMessage()
			);
		}

		$this->redirect('parametres_taux_tva');
	}
	public function setDefaultTauxTva(): void
	{
		try {

			(new TauxTvaRepository())->setDefault(

				(int) Request::post('id')

			);

			Session::flash(
				'success',
				'TVA par défaut modifiée.'
			);

		} catch (\Throwable $exception) {

			Session::flash(
				'error',
				$exception->getMessage()
			);
		}

		$this->redirect('parametres_taux_tva');
	}
	public function deleteTauxTva(): void
	{
		try {

			(new TauxTvaRepository())->deactivate(

				(int) Request::post('id')

			);

			Session::flash(
				'success',
				'TVA désactivée.'
			);

		} catch (\Throwable $exception) {

			Session::flash(
				'error',
				$exception->getMessage()
			);
		}

		$this->redirect('parametres_taux_tva');
	}
	public function modesReglement(): void
{
    $repository = new ModeReglementRepository();

    $this->view('parametres/modes_reglement', [
        'title' => 'Modes de règlement',
        'modesReglement' => $repository->all(),
    ]);
}

	public function storeModeReglement(): void
	{
		try {
			$libelle = trim((string) Request::post('libelle', ''));
			$comptant = (int) Request::post('comptant', 0);
			$delai = (int) Request::post('delai_jours', 0);
			$ordre = (int) Request::post('ordre_affichage', 0);

			if ($libelle === '') {
				throw new \InvalidArgumentException(
					'Le libellé est obligatoire.'
				);
			}

			if ($delai < 0) {
				throw new \InvalidArgumentException(
					'Le délai ne peut pas être négatif.'
				);
			}

			if ($ordre <= 0) {
				throw new \InvalidArgumentException(
					'L’ordre d’affichage doit être supérieur à zéro.'
				);
			}

			if ($comptant === 1) {
				$delai = 0;
			}

			(new ModeReglementRepository())->create(
				$libelle,
				$comptant,
				$delai,
				$ordre
			);

			Session::flash(
				'success',
				'Mode de règlement ajouté.'
			);
		} catch (\Throwable $exception) {
			Session::flash(
				'error',
				$exception->getMessage()
			);
		}

		$this->redirect('parametres_modes_reglement');
	}

	public function updateModeReglement(): void
	{
		try {
			$id = (int) Request::post('id', 0);
			$libelle = trim((string) Request::post('libelle', ''));
			$comptant = (int) Request::post('comptant', 0);
			$delai = (int) Request::post('delai_jours', 0);
			$ordre = (int) Request::post('ordre_affichage', 0);
			$actif = (int) Request::post('actif', 0);

			if ($id <= 0) {
				throw new \InvalidArgumentException(
					'Mode de règlement invalide.'
				);
			}

			if ($libelle === '') {
				throw new \InvalidArgumentException(
					'Le libellé est obligatoire.'
				);
			}

			if ($delai < 0) {
				throw new \InvalidArgumentException(
					'Le délai ne peut pas être négatif.'
				);
			}

			if ($ordre <= 0) {
				throw new \InvalidArgumentException(
					'L’ordre d’affichage doit être supérieur à zéro.'
				);
			}

			if ($comptant === 1) {
				$delai = 0;
			}

			(new ModeReglementRepository())->update(
				$id,
				$libelle,
				$comptant,
				$delai,
				$ordre,
				$actif
			);

			Session::flash(
				'success',
				'Mode de règlement mis à jour.'
			);
		} catch (\Throwable $exception) {
			Session::flash(
				'error',
				$exception->getMessage()
			);
		}

		$this->redirect('parametres_modes_reglement');
	}

	public function deleteModeReglement(): void
	{
		try {
			$id = (int) Request::post('id', 0);

			if ($id <= 0) {
				throw new \InvalidArgumentException(
					'Mode de règlement invalide.'
				);
			}

			(new ModeReglementRepository())->deactivate($id);

			Session::flash(
				'success',
				'Mode de règlement désactivé.'
			);
		} catch (\Throwable $exception) {
			Session::flash(
				'error',
				$exception->getMessage()
			);
		}

		$this->redirect('parametres_modes_reglement');
	}
	public function numerotation(): void
	{
		$repository = new NumerotationRepository();

		$this->view('parametres/numerotation', [
			'title' => 'Numérotation',
			'numerotations' => $repository->all(),
		]);
	}

	public function updateNumerotation(): void
	{
		try {
			$id = (int) Request::post('id', 0);
			$prefixe = trim((string) Request::post('prefixe', ''));
			$longueurCompteur = (int) Request::post('longueur_compteur', 6);
			$remiseZeroAnnuelle = (int) Request::post('remise_zero_annuelle', 1);
			$actif = (int) Request::post('actif', 1);

			if ($id <= 0) {
				throw new \InvalidArgumentException(
					'Paramètre de numérotation invalide.'
				);
			}

			if ($prefixe === '') {
				throw new \InvalidArgumentException(
					'Le préfixe est obligatoire.'
				);
			}

			if ($longueurCompteur < 3 || $longueurCompteur > 10) {
				throw new \InvalidArgumentException(
					'La longueur du compteur doit être comprise entre 3 et 10 chiffres.'
				);
			}

			(new NumerotationRepository())->update(
				$id,
				$prefixe,
				$longueurCompteur,
				$remiseZeroAnnuelle,
				$actif
			);

			Session::flash(
				'success',
				'Paramètre de numérotation mis à jour.'
			);
		} catch (\Throwable $exception) {
			Session::flash(
				'error',
				$exception->getMessage()
			);
		}

		$this->redirect('parametres_numerotation');
	}
	public function documents(): void
{
    $settings = (new ParametreSocieteService())->get();

    $this->view('parametres/documents', [
        'title' => 'Paramètres documents',
        'settings' => $settings,
        'errors' => [],
    ]);
}

public function saveDocuments(): void
{
    $service = new ParametreSocieteService();
    $data = Request::all();

    try {
        $logoFile = $_FILES['logo_file'] ?? null;

        if (
            is_array($logoFile)
            && ($logoFile['error'] ?? UPLOAD_ERR_NO_FILE) !== UPLOAD_ERR_NO_FILE
        ) {
            if (($logoFile['error'] ?? UPLOAD_ERR_NO_FILE) !== UPLOAD_ERR_OK) {
                throw new \RuntimeException(
                    'Le téléchargement du logo a échoué.'
                );
            }

            $size = (int)($logoFile['size'] ?? 0);

            if ($size <= 0 || $size > 2 * 1024 * 1024) {
                throw new \RuntimeException(
                    'Le logo doit avoir une taille maximale de 2 Mo.'
                );
            }

            $temporaryPath = (string)($logoFile['tmp_name'] ?? '');

            if ($temporaryPath === '' || !is_uploaded_file($temporaryPath)) {
                throw new \RuntimeException(
                    'Le fichier du logo est invalide.'
                );
            }

            $finfo = new \finfo(FILEINFO_MIME_TYPE);
            $mimeType = (string)$finfo->file($temporaryPath);

            $allowedMimeTypes = [
                'image/png' => 'png',
                'image/jpeg' => 'jpg',
            ];

            if (!isset($allowedMimeTypes[$mimeType])) {
                throw new \RuntimeException(
                    'Le logo doit être au format PNG, JPG ou JPEG.'
                );
            }

            $extension = $allowedMimeTypes[$mimeType];

            $rootPath = dirname(__DIR__, 2);
            $logoDirectory = $rootPath
                . DIRECTORY_SEPARATOR
                . 'public'
                . DIRECTORY_SEPARATOR
                . 'assets'
                . DIRECTORY_SEPARATOR
                . 'img';

            if (
                !is_dir($logoDirectory)
                && !mkdir($logoDirectory, 0775, true)
                && !is_dir($logoDirectory)
            ) {
                throw new \RuntimeException(
                    'Impossible de créer le dossier destiné au logo.'
                );
            }

            if (!is_writable($logoDirectory)) {
                throw new \RuntimeException(
                    'Le dossier public/assets/img n’est pas accessible en écriture.'
                );
            }

            $fileName = 'logo_societe.' . $extension;
            $destination = $logoDirectory
                . DIRECTORY_SEPARATOR
                . $fileName;

            if (!move_uploaded_file($temporaryPath, $destination)) {
                throw new \RuntimeException(
                    'Impossible d’enregistrer le logo.'
                );
            }

            foreach (['png', 'jpg'] as $oldExtension) {
                if ($oldExtension === $extension) {
                    continue;
                }

                $oldFile = $logoDirectory
                    . DIRECTORY_SEPARATOR
                    . 'logo_societe.'
                    . $oldExtension;

                if (is_file($oldFile)) {
                    unlink($oldFile);
                }
            }

            $data['logo_path'] =
                'assets/img/' .
                $fileName .
                '?v=' .
                time();
        }

        $service->saveDocuments($data);

        Session::flash(
            'success',
            'Paramètres des documents enregistrés.'
        );

        $this->redirect('parametres_documents');
    } catch (\Throwable $exception) {
        $currentSettings = $service->get();

        Session::flash(
            'error',
            'Enregistrement impossible : ' .
            $exception->getMessage()
        );

        $this->view('parametres/documents', [
            'title' => 'Paramètres documents',
            'settings' => array_replace($currentSettings, $data),
            'errors' => [
                'general' => $exception->getMessage(),
            ],
        ]);
    }
}
public function removeDocumentLogo(): void
{
    try {
        (new ParametreSocieteService())->removeLogo();

        Session::flash(
            'success',
            'Le logo de l’entreprise a été supprimé.'
        );
    } catch (\Throwable $exception) {
        Session::flash(
            'error',
            'Suppression impossible : ' . $exception->getMessage()
        );
    }

    $this->redirect('parametres_documents');
}	
}
