<?php

/*
 * This file is part of the VITICORE2 package.
 *
 * (c) CP Creation <web@cpcreation.fr>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace CpCreation\VitiCore\Bridge\Symfony\Bundle\Seed;

use CpCreation\VitiCore\Contact\Model\Contact;
use CpCreation\VitiCore\Locale\Model\Locale;
use CpCreation\VitiCore\Product\Model\ProductCategory;
use CpCreation\VitiCore\Product\Model\ProductPriceGroup;
use CpCreation\VitiCore\Product\Model\ProductTax;
use CpCreation\VitiCore\Product\Model\ProductType;
use CpCreation\VitiCore\Product\Model\Translation\ProductCategoryTranslation;
use CpCreation\VitiCore\Product\Model\Translation\ProductTypeTranslation;
use CpCreation\VitiCore\Seed\SeederInterface;
use CpCreation\VitiCore\Seed\SeedPayload;
use CpCreation\VitiCore\Shop\Model\ShippingCountry;
use CpCreation\VitiCore\Shop\Model\ShippingCounty;
use CpCreation\VitiCore\Shop\Model\ShippingPrice;
use CpCreation\VitiCore\Shop\Model\ShippingZone;
use CpCreation\VitiCore\Shop\Model\ShopConfig;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\DependencyInjection\Attribute\AsTaggedItem;

#[AsTaggedItem(index: 'core', priority: 100)]
class CoreSeed implements SeederInterface
{
    public function __construct(private EntityManagerInterface $entityManager)
    {
    }

    public function isEnabled(): bool
    {
        return true;
    }

    /** Version cible (monotone croissante) */
    public function version(): int
    {
        return 1;
    }

    /**
     * Applique les deltas depuis $fromVersion (0..n) -> targetVersion.
     * Doit être idempotent (upsert) et ne pas écraser les modifs user.
     */
    public function seed(SeedPayload $seedPayload, int $fromVersion): void
    {
        for ($version = $fromVersion + 1; $version <= $this->version(); ++$version) {
            $method = 'v'.$version;

            if (!method_exists($this, $method)) {
                throw new \LogicException(\sprintf('Missing seed step method "%s" for "%s".', $method, static::class));
            }

            $this->{$method}();
        }
    }

    private function v1(): void
    {
        $group = $this->entityManager->getRepository(ProductPriceGroup::class)->findOneBy([
            'name' => 'Public',
        ]);

        if (!$group instanceof ProductPriceGroup) {
            $group = new ProductPriceGroup();
            $group->setName('Public');
            $group->setByDefault(true);
            $this->entityManager->persist($group);
        }

        $lang = $this->entityManager->getRepository(Locale::class)->findOneBy([
            'locale' => 'en',
        ]);

        if (!$lang instanceof Locale) {
            $lang = new Locale();
            $lang->setName('Anglais');
            $lang->setLocale('en');
            $this->entityManager->persist($lang);
        }

        $tax = $this->entityManager->getRepository(ProductTax::class)->findOneBy([
            'name' => 'TVA 20%',
        ]);

        if (!$tax instanceof ProductTax) {
            $tax = new ProductTax();
            $tax->setName('TVA 20%');
            $tax->setByDefault(true);
            $tax->setInPro(true);
            $tax->setInCustomer(true);
            $tax->setOutCustomer(true);
            $tax->setOutPro(true);
            $tax->setValue(0.2);
            $this->entityManager->persist($tax);
        }

        $shopConfig = $this->entityManager->getRepository(ShopConfig::class)->findOneBy([]);
        if (!$shopConfig instanceof ShopConfig) {
            $shopConfig = new ShopConfig();
            $this->entityManager->persist($shopConfig);
        }

        $contact = $this->entityManager->getRepository(Contact::class)->findOneBy([]);
        if (!$contact instanceof Contact) {
            $contact = new Contact();
            $contact->setCgv("<p><b>Article 1 : Champ d'application</b></p><p>Toutes nos ventes sont régies par les présentes conditions générales de vente qui prévalent sur toute condition d'achat, sauf stipulation dérogatoire expresse.</p><p><b>Article 2 : Prix</b></p><p>Les prix applicables sont ceux en vigueur au jour de la prise de commande, et figurent sur le barème ci-contre, libellés en euros.</p><p>Ils s'entendent « départ cellier », le transport étant à la charge de l'acheteur.</p><p>Sauf accord entre les parties, le règlement s'effectue à la commande.</p><p>Si un délai est accordé, aucun escompte ne sera consenti en cas de paiement anticipé.</p><p>Tout règlement intervenant après la date de paiement figurant sur la facture entraînera le paiement de pénalités de retard dont le montant est égal à trois fois le taux de l'intérêt légal. Ces pénalités sont exigibles sans qu'un rappel soit nécessaire. En outre, l'ensemble des frais de mise en recouvrement seront mis à la charge de l'acheteur.</p><p>En application des dispositions légales, tout professionnel en situation de retard de paiement sera débiteur à l'égard du créancier d'une indemnité forfaitaire de 40 € pour frais de recouvrement. Toutefois, si les frais de recouvrement sont supérieurs au montant de cette indemnité, le créancier pourra demander une indemnisation supplémentaire, sur justification.</p><p><b>Article 3 : Droit de rétractation</b></p><p>– Si le client est un professionnel Aucun droit de rétractation ne lui est accordé.</p><p>– Si le client est un consommateur particulier</p><p>En cas de vente conclue à distance ou hors établissement, le client dispose d'un délai de 14 jours à compter du jour de la réception des vins pour se rétracter. Il peut utiliser le formulaire de rétractation ci-joint, mais ce n'est pas obligatoire.</p><p>Le viticulteur remboursera alors le consommateur de tous les paiements reçus, dès réception des biens en retour.</p><p>Le viticulteur procédera au remboursement en utilisant le même moyen de paiement que celui que le client aura utilisé pour la transaction initiale, sauf s'il est convenu d'un moyen différent.</p><p>En tout état de cause, ce remboursement n'occasionnera pas de frais pour le client.</p><p>Si au moment de la rétractation le client a reçu les bouteilles, il doit les renvoyer à l'adresse de l'exploitation sans retard excessif, et en tout état de cause, au plus tard quatorze jours après sa notification de rétractation. Ce délai est réputé respecté si le bien est renvoyé avant l'expiration du délai de quatorze jours.</p><p>Les frais directs de renvoi du bien sont à la charge du client.</p><p>La responsabilité du client pourra être engagée en cas de dépréciation des biens résultant de manipulations autres que celles nécessaires pour établir la nature, les caractéristiques et le bon fonctionnement de ces biens.</p><p>– Si la vente a été conclue sur une foire ou un salon Le client ne dispose d'aucun droit de rétractation.</p><p><b>Article 4 : Réserve de propriété</b></p><p>Le vendeur conserve la propriété des biens vendus jusqu'à complet paiement du prix par le client, en principal et accessoires. Toutefois, dès la livraison, les risques de perte ou de détérioration sont transférés à l'acheteur.</p><p><b>Article 5 : Livraison</b></p><p>La livraison est effectuée :</p><p>– soit par la remise directe de la marchandise à l'acheteur</p><p>– soit au lieu indiqué par l'acheteur sur le bon de commande.</p><p>Nos vins voyagent aux risques et périls du destinataire, même en cas d'expédition franco. Le vendeur ne pourra être tenu pour responsable en cas d'avarie, de perte, de vol ou de colis défectueux. En conséquence, les clients sont invités à vérifier les colis à leur réception et à notifier toute réserve au transporteur, par lettre recommandée, dans les trois jours ouvrables qui suivent la réception de la marchandise.</p><p><b>Article 6 : Litiges</b></p><p>Nos ventes sont soumises à la législation française.</p><p>Il est expressément attribué compétence au tribunal de grande instance du domicile du vendeur.</p><p></p>");
            $contact->setCity('Epernay');
            $contact->setAddress('Rue de la mairie');
            $contact->setCompany('SAS Champagne');
            $contact->setPostal('51200');
            $contact->setCity('Epernay');
            $contact->setFirstname('Bertrand');
            $contact->setLastname('Girard');
            $contact->setPhone1('0123456789');
            $contact->setEmailFrom('web@cpcreation.fr');
            $contact->setEmailToMessage('web@cpcreation.fr');
            $contact->setEmailToShop('web@cpcreation.fr');
            $contact->setEditorAddress('Rue de la mairie');
            $contact->setEditorCity('Epernay');
            $contact->setEditorCompany('SAS Champagne');
            $contact->setEditorPostal('51200');
            $contact->setEditorRcs('888888888');
            $contact->setEditorTva('FR8888888888');
            $contact->setCommitteeChampagneIdentifiant('FR246127_01QEKR');
            $contact->setCommitteeChampagneSiret('SIRET 78038582900012');
            $contact->setRecaptcha(true);
            $this->entityManager->persist($contact);
        }

        $champagneCategory = $this->findProductCategoryByName('Champagne');
        if (!$champagneCategory instanceof ProductCategory) {
            $champagneCategory = new ProductCategory();

            $champagneCategoryFr = new ProductCategoryTranslation();
            $champagneCategoryFr->setLocale('fr');
            $champagneCategoryFr->setName('Champagne');
            $champagneCategory->addTranslation($champagneCategoryFr);

            $champagneCategoryEn = new ProductCategoryTranslation();
            $champagneCategoryEn->setLocale('en');
            $champagneCategoryEn->setName('Champagne');
            $champagneCategory->addTranslation($champagneCategoryEn);

            $this->entityManager->persist($champagneCategory);
        }

        // Demi-Bouteille
        $typeHalfBottle = $this->findProductTypeByName('Demi-Bouteille');
        if (!$typeHalfBottle instanceof ProductType) {
            $typeHalfBottle = new ProductType();
            $typeHalfBottleFr = new ProductTypeTranslation();
            $typeHalfBottleFr->setLocale('fr');
            $typeHalfBottleFr->setName('Demi-Bouteille');
            $typeHalfBottle->addTranslation($typeHalfBottleFr);
            $typeHalfBottleEn = new ProductTypeTranslation();
            $typeHalfBottleEn->setLocale('en');
            $typeHalfBottleEn->setName('Half-bottle');
            $typeHalfBottle->addTranslation($typeHalfBottleEn);
            $typeHalfBottle->setVolume(37.5);
            $typeHalfBottle->setUnity('cl');
            $typeHalfBottle->setMultipleQuantityCart(6);
            $typeHalfBottle->setEquivalency(0.5);
            $typeHalfBottle->setEquivalencyManu(0.5);
            $typeHalfBottle->setEquivalencyDegressive(0.5);
            $typeHalfBottle->setEquivalencyFreeShipping(0.5);
            $typeHalfBottle->setEquivalencyOnShipping(true);
            $typeHalfBottle->setEquivalencyOnFreeShipping(true);
            $this->entityManager->persist($typeHalfBottle);
        }

        // Bouteille
        $typeBottle = $this->findProductTypeByName('Bouteille');
        if (!$typeBottle instanceof ProductType) {
            $typeBottle = new ProductType();
            $typeBottleFr = new ProductTypeTranslation();
            $typeBottleFr->setLocale('fr');
            $typeBottleFr->setName('Bouteille');
            $typeBottle->addTranslation($typeBottleFr);
            $typeBottleEn = new ProductTypeTranslation();
            $typeBottleEn->setLocale('en');
            $typeBottleEn->setName('Bottle');
            $typeBottle->addTranslation($typeBottleEn);
            $typeBottle->setEquivalencyDefault(true);
            $typeBottle->setVolume(75);
            $typeBottle->setUnity('cl');
            $typeBottle->setMultipleQuantityCart(1);
            $typeBottle->setEquivalency(1);
            $typeBottle->setEquivalencyManu(1);
            $typeBottle->setEquivalencyDegressive(1);
            $typeBottle->setEquivalencyFreeShipping(1);
            $typeBottle->setOrderWithaMinimumEquivalency(6);
            $typeBottle->setEquivalencyOnShipping(true);
            $typeBottle->setEquivalencyOnFreeShipping(true);
            $this->entityManager->persist($typeBottle);
        }

        // Magnum
        $typeMagnum = $this->findProductTypeByName('Magnum');
        if (!$typeMagnum instanceof ProductType) {
            $typeMagnum = new ProductType();
            $typeMagnumFr = new ProductTypeTranslation();
            $typeMagnumFr->setLocale('fr');
            $typeMagnumFr->setName('Magnum');
            $typeMagnum->addTranslation($typeMagnumFr);
            $typeMagnumEn = new ProductTypeTranslation();
            $typeMagnumEn->setLocale('en');
            $typeMagnumEn->setName('Magnum');
            $typeMagnum->addTranslation($typeMagnumEn);
            $typeMagnum->setVolume(1.5);
            $typeMagnum->setUnity('L');
            $typeMagnum->setMultipleQuantityCart(1);
            $typeMagnum->setEquivalency(2);
            $typeMagnum->setEquivalencyManu(2);
            $typeMagnum->setEquivalencyDegressive(2);
            $typeMagnum->setEquivalencyFreeShipping(2);
            $typeMagnum->setEquivalencyOnShipping(true);
            $typeMagnum->setEquivalencyOnFreeShipping(true);
            $this->entityManager->persist($typeMagnum);
        }

        // Jéro
        $typeJero = $this->findProductTypeByName('Jeroboam');
        if (!$typeJero instanceof ProductType) {
            $typeJero = new ProductType();
            $typeJeroFr = new ProductTypeTranslation();
            $typeJeroFr->setLocale('fr');
            $typeJeroFr->setName('Jeroboam');
            $typeJero->addTranslation($typeJeroFr);
            $typeJeroEn = new ProductTypeTranslation();
            $typeJeroEn->setLocale('en');
            $typeJeroEn->setName('Jeroboam');
            $typeJero->addTranslation($typeJeroEn);
            $typeJero->setVolume(3);
            $typeJero->setUnity('L');
            $typeJero->setMultipleQuantityCart(1);
            $typeJero->setEquivalency(4);
            $typeJero->setEquivalencyManu(4);
            $typeJero->setEquivalencyDegressive(4);
            $typeJero->setEquivalencyFreeShipping(4);
            $typeJero->setEquivalencyOnShipping(true);
            $typeJero->setEquivalencyOnFreeShipping(true);
            $this->entityManager->persist($typeJero);
        }

        foreach ($this->shippingCountriesData() as $code => $config) {
            $country = $this->entityManager->getRepository(ShippingCountry::class)->findOneBy([
                'code' => $code,
            ]);

            if (!$country instanceof ShippingCountry) {
                $country = new ShippingCountry();
                $country->setCode($code);
                $this->entityManager->persist($country);
            }

            $country->setCounty($config['county']);
            $country->setDisabled($config['disabled']);

            if (!$country->getGroups()->contains($group)) {
                $country->addGroup($group);
            }
        }

        foreach ($this->shippingCountiesData() as $code) {
            $county = $this->entityManager->getRepository(ShippingCounty::class)->findOneBy([
                'code' => $code,
            ]);

            if ($county instanceof ShippingCounty) {
                continue;
            }

            $county = new ShippingCounty();
            $county->setCode($code);
            $this->entityManager->persist($county);
        }

        foreach ($this->shippingZonesData() as $name => $config) {
            $zone = $this->entityManager->getRepository(ShippingZone::class)->findOneBy([
                'name' => $name,
            ]);

            if (!$zone instanceof ShippingZone) {
                $zone = new ShippingZone();
                $zone->setName($name);
                $this->entityManager->persist($zone);
            }

            foreach ($config['countries'] as $countryCode) {
                $country = $this->entityManager->getRepository(ShippingCountry::class)->findOneBy([
                    'code' => $countryCode,
                ]);

                if ($country instanceof ShippingCountry) {
                    $zone->addCountry($country);
                }
            }

            foreach ($config['counties'] as $countyCode) {
                $county = $this->entityManager->getRepository(ShippingCounty::class)->findOneBy([
                    'code' => $countyCode,
                ]);

                if ($county instanceof ShippingCounty) {
                    $zone->addCounty($county);
                }
            }
        }

        foreach ($this->shippingPricesData() as $config) {
            $shippingPrice = $this->entityManager->getRepository(ShippingPrice::class)->findOneBy([
                'qtyOf' => $config['qtyOf'],
                'qtyAt' => $config['qtyAt'],
                'packagePrice' => $config['packagePrice'],
                'nameCarrier' => $config['nameCarrier'],
                'deliveryMethod' => null,
            ]);

            if (!$shippingPrice instanceof ShippingPrice) {
                $shippingPrice = new ShippingPrice();
                $shippingPrice->setQtyOf($config['qtyOf']);
                $shippingPrice->setQtyAt($config['qtyAt']);
                $shippingPrice->setPackagePrice($config['packagePrice']);
                $shippingPrice->setNameCarrier($config['nameCarrier']);
                $this->entityManager->persist($shippingPrice);
            }

            if (!$shippingPrice->getTypes()->contains($typeBottle)) {
                $shippingPrice->addType($typeBottle);
            }

            if (!$shippingPrice->getGroups()->contains($group)) {
                $shippingPrice->addGroup($group);
            }

            foreach ($config['zones'] as $zoneName) {
                $zone = $this->entityManager->getRepository(ShippingZone::class)->findOneBy([
                    'name' => $zoneName,
                ]);

                if ($zone instanceof ShippingZone && !$shippingPrice->getZones()->contains($zone)) {
                    $shippingPrice->addZone($zone);
                }
            }
        }
    }

    /**
     * @return array<string, array{county: bool, disabled: bool}>
     */
    private function shippingCountriesData(): array
    {
        return [
            'DE' => ['county' => false, 'disabled' => true],
            'AT' => ['county' => false, 'disabled' => true],
            'BE' => ['county' => false, 'disabled' => true],
            'BG' => ['county' => false, 'disabled' => true],
            'CY' => ['county' => false, 'disabled' => true],
            'HR' => ['county' => false, 'disabled' => true],
            'DK' => ['county' => false, 'disabled' => true],
            'ES' => ['county' => false, 'disabled' => true],
            'EE' => ['county' => false, 'disabled' => true],
            'FI' => ['county' => false, 'disabled' => true],
            'FR' => ['county' => true, 'disabled' => false],
            'GR' => ['county' => false, 'disabled' => true],
            'HU' => ['county' => false, 'disabled' => true],
            'IE' => ['county' => false, 'disabled' => true],
            'IT' => ['county' => false, 'disabled' => true],
            'LV' => ['county' => false, 'disabled' => true],
            'LT' => ['county' => false, 'disabled' => true],
            'MT' => ['county' => false, 'disabled' => true],
            'LU' => ['county' => false, 'disabled' => true],
            'NL' => ['county' => false, 'disabled' => true],
            'PL' => ['county' => false, 'disabled' => true],
            'PT' => ['county' => false, 'disabled' => true],
            'CZ' => ['county' => false, 'disabled' => true],
            'RO' => ['county' => false, 'disabled' => true],
            'GB' => ['county' => false, 'disabled' => true],
            'SK' => ['county' => false, 'disabled' => true],
            'SI' => ['county' => false, 'disabled' => true],
            'SE' => ['county' => false, 'disabled' => true],
        ];
    }

    /**
     * @return list<string>
     */
    private function shippingCountiesData(): array
    {
        return [
            '01', '02', '03', '04', '05', '06', '07', '08', '09',
            '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20',
            '21', '22', '23', '24', '25', '26', '27', '28', '29',
            '30', '31', '32', '33', '34', '35', '36', '37', '38', '39',
            '40', '41', '42', '43', '44', '45', '46', '47', '48', '49',
            '50', '51', '52', '53', '54', '55', '56', '57', '58', '59',
            '60', '61', '62', '63', '64', '65', '66', '67', '68', '69',
            '70', '71', '72', '73', '74', '75', '76', '77', '78', '79',
            '80', '81', '82', '83', '84', '85', '86', '87', '88', '89',
            '90', '91', '92', '93', '94', '95', '98',
        ];
    }

    /**
     * @return array<string, array{countries: list<string>, counties: list<string>}>
     */
    private function shippingZonesData(): array
    {
        return [
            'Zone 1 - France' => [
                'countries' => ['FR'],
                'counties' => [
                    '02', '08', '10', '14', '18', '21', '25', '27', '28', '36', '37', '39', '41', '45',
                    '51', '52', '54', '55', '57', '58', '59', '60', '61', '62', '67', '68', '70', '71',
                    '72', '75', '76', '77', '78', '80', '88', '89', '90', '91', '92', '93', '94', '95',
                    '01', '03', '17', '12', '15', '16', '17', '19', '22', '23', '24', '26', '29', '33',
                    '35', '38', '42', '43', '44', '46', '47', '48', '49', '50', '53', '56', '63', '69',
                    '73', '74', '79', '85', '86', '87', '04', '05', '06', '07', '09', '11', '13', '30',
                    '31', '32', '34', '40', '64', '65', '66', '81', '82', '83', '84', '98',
                ],
            ],
            'Zone 2 - Corse - France' => [
                'countries' => ['FR'],
                'counties' => ['20'],
            ],
            'Belgique' => [
                'countries' => ['BE'],
                'counties' => [],
            ],
            'Zone 1 - UE' => [
                'countries' => ['DE', 'GB', 'IT', 'LU', 'NL'],
                'counties' => [],
            ],
            'Zone 2 - UE' => [
                'countries' => ['AT', 'DK', 'ES', 'FI', 'PT', 'IE', 'SE'],
                'counties' => [],
            ],
        ];
    }

    /**
     * @return list<array{qtyOf: int, qtyAt: int, packagePrice: int, zones: list<string>, nameCarrier: string}>
     */
    private function shippingPricesData(): array
    {
        return [
            ['qtyOf' => 0, 'qtyAt' => 1, 'packagePrice' => 1100, 'zones' => ['Zone 1 - France', 'Zone 2 - Corse - France'], 'nameCarrier' => 'Colissimo'],
            ['qtyOf' => 1, 'qtyAt' => 2, 'packagePrice' => 1300, 'zones' => ['Zone 1 - France', 'Zone 2 - Corse - France'], 'nameCarrier' => 'Colissimo'],
            ['qtyOf' => 2, 'qtyAt' => 3, 'packagePrice' => 1500, 'zones' => ['Zone 1 - France', 'Zone 2 - Corse - France'], 'nameCarrier' => 'Colissimo'],
            ['qtyOf' => 3, 'qtyAt' => 6, 'packagePrice' => 1950, 'zones' => ['Zone 1 - France', 'Zone 2 - Corse - France'], 'nameCarrier' => 'Colissimo'],
            ['qtyOf' => 6, 'qtyAt' => 42, 'packagePrice' => 2600, 'zones' => ['Zone 1 - France', 'Zone 2 - Corse - France'], 'nameCarrier' => 'Colissimo'],
        ];
    }

    private function findProductTypeByName(string $name): ?ProductType
    {
        $types = $this->entityManager->getRepository(ProductType::class)
            ->createQueryBuilder('productType')
            ->innerJoin('productType.translations', 'translation')
            ->andWhere('translation.name = :name')
            ->setParameter('name', $name)
            ->setMaxResults(1)
            ->getQuery()
            ->getResult();

        return $types[0] ?? null;
    }

    private function findProductCategoryByName(string $name): ?ProductCategory
    {
        $categories = $this->entityManager->getRepository(ProductCategory::class)
            ->createQueryBuilder('productCategory')
            ->innerJoin('productCategory.translations', 'translation')
            ->andWhere('translation.name = :name')
            ->setParameter('name', $name)
            ->setMaxResults(1)
            ->getQuery()
            ->getResult();

        return $categories[0] ?? null;
    }
}
