<?php

declare(strict_types=1);

namespace App\Command\Import;

use App\Entity\Zone;
use App\Entity\Location;
use App\Entity\ShippingCompany;
use App\Entity\Vessel;
use App\Entity\Trip;
use DateTimeImmutable;
use Doctrine\ORM\EntityManagerInterface;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Shared\Date;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;

#[AsCommand(
    name: 'app:import-excel',
    description: 'Import excel base data'
)]
class ImportExcelCommand extends Command
{
    public function __construct(
        private readonly EntityManagerInterface $entityManager,
        private readonly ParameterBagInterface $params
    ) {
        parent::__construct();
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = new SymfonyStyle($input, $output);

        // Pfad zur Excel-Datei (passen Sie diesen Pfad an Ihre Bedürfnisse an)
        $filePath = $this->params->get('kernel.project_dir') . '/src/Command/Import/Import-Template.xlsx';

        if (!file_exists($filePath)) {
            $io->error('Excel file not found: ' . $filePath);
            return Command::FAILURE;
        }

        // Starte Transaktion
        $this->entityManager->beginTransaction();

        try {
            $io->title('Starting Excel Import');

            // Lade die Excel-Datei
            $spreadsheet = IOFactory::load($filePath);

            // Importiere in der richtigen Reihenfolge (Abhängigkeiten beachten)
            $this->importZones($spreadsheet, $io);
            $this->entityManager->flush(); // Flush nach Zones

            $this->importLocations($spreadsheet, $io);
            $this->entityManager->flush(); // Flush nach Locations

            $this->importShippingCompanies($spreadsheet, $io);
            $this->entityManager->flush(); // Flush nach ShippingCompanies

            $this->importVessels($spreadsheet, $io);
            $this->entityManager->flush(); // Flush nach Vessels

            $this->importTrips($spreadsheet, $io);
            $this->entityManager->flush(); // Finaler Flush

            // Commit Transaktion bei Erfolg
            $this->entityManager->commit();

            $io->success('Excel import completed successfully!');
            return Command::SUCCESS;

        } catch (\Exception $e) {
            // Rollback bei Fehler
            $this->entityManager->rollback();

            $io->error('Import failed: ' . $e->getMessage());
            return Command::FAILURE;
        }
    }

    private function importZones($spreadsheet, SymfonyStyle $io): void
    {
        $io->section('Importing Zones');

        $sheet = $spreadsheet->getSheetByName('zones');
        if (!$sheet) {
            $io->warning('Sheet "zones" not found');
            return;
        }

        $rows = $sheet->toArray();
        $headers = array_shift($rows);

        $count = 0;
        foreach ($rows as $row) {
            $data = array_combine($headers, $row);

            // Prüfe, ob Zone bereits existiert
            $existingZone = $this->entityManager->getRepository(Zone::class)
                ->findOneBy(['name' => $data['name']]);

            if (!$existingZone) {
                $zone = new Zone($data['name']);

                $this->entityManager->persist($zone);
                $count++;
            }
        }

        $io->success("Imported $count zones");
    }

    private function importLocations($spreadsheet, SymfonyStyle $io): void
    {
        $io->section('Importing Locations');

        $sheet = $spreadsheet->getSheetByName('locations');
        if (!$sheet) {
            $io->warning('Sheet "locations" not found');
            return;
        }

        $rows = $sheet->toArray();
        $headers = array_shift($rows);

        $count = 0;
        foreach ($rows as $row) {
            $data = array_combine($headers, $row);

            // Prüfe, ob Location bereits existiert
            $existingLocation = $this->entityManager->getRepository(Location::class)
                ->findOneBy(['name' => $data['name']]);

            if (!$existingLocation) {
                // Finde die zugehörige Zone
                $zone = $this->entityManager->getRepository(Zone::class)
                    ->findOneBy(['name' => $data['zone']]);

                if ($zone) {
                    // Generiere einen Code aus dem Namen (oder verwenden Sie Ihre eigene Logik)
                    $code = strtoupper(substr(preg_replace('/[^a-zA-Z0-9]/', '', $data['name']), 0, 3));

                    $location = new Location($zone, $data['name'], $code);

                    $this->entityManager->persist($location);
                    $count++;
                } else {
                    $io->warning("Zone '{$data['zone']}' not found for location '{$data['name']}'");
                }
            }
        }

        $io->success("Imported $count locations");
    }

    private function importShippingCompanies($spreadsheet, SymfonyStyle $io): void
    {
        $io->section('Importing Shipping Companies');

        $sheet = $spreadsheet->getSheetByName('shipping_companies');
        if (!$sheet) {
            $io->warning('Sheet "shipping_companies" not found');
            return;
        }

        $rows = $sheet->toArray();
        $headers = array_shift($rows);

        $count = 0;
        foreach ($rows as $row) {
            $data = array_combine($headers, $row);

            // Prüfe, ob ShippingCompany bereits existiert
            $existingCompany = $this->entityManager->getRepository(ShippingCompany::class)
                ->findOneBy(['code' => $data['code']]);

            if (!$existingCompany) {
                $company = new ShippingCompany($data['name'], $data['code']);

                $this->entityManager->persist($company);
                $count++;
            }
        }

        $io->success("Imported $count shipping companies");
    }

    private function importVessels($spreadsheet, SymfonyStyle $io): void
    {
        $io->section('Importing Vessels');

        $sheet = $spreadsheet->getSheetByName('vessel');
        if (!$sheet) {
            $io->warning('Sheet "vessel" not found');
            return;
        }

        $rows = $sheet->toArray();
        $headers = array_shift($rows);

        $count = 0;
        foreach ($rows as $row) {
            $data = array_combine($headers, $row);

            // Prüfe, ob Vessel bereits existiert
            $existingVessel = $this->entityManager->getRepository(Vessel::class)
                ->findOneBy(['code' => $data['code']]);

            if (!$existingVessel) {
                // Finde die zugehörige Shipping Company
                $company = $this->entityManager->getRepository(ShippingCompany::class)
                    ->findOneBy(['name' => $data['shipping_company']]);

                if ($company) {
                    $vessel = new Vessel($company, $data['name'], $data['code']);

                    // Setze optionale Felder
                    if (isset($data['length'])) {
                        $vessel->setLength((float)$data['length']);
                    }
                    if (isset($data['breadth'])) {
                        $vessel->setBreadth((float)$data['breadth']);
                    }
                    if (isset($data['draft'])) {
                        $vessel->setDraft((float)$data['draft']);
                    }
                    if (isset($data['gross_tonnage'])) {
                        $vessel->setGrossTonnage((float)$data['gross_tonnage']);
                    }
                    if (isset($data['imo_np'])) {
                        $vessel->setImoNo($data['imo_np']);
                    }
                    if (isset($data['call_sign'])) {
                        $vessel->setCallSign($data['call_sign']);
                    }

                    $this->entityManager->persist($vessel);
                    $count++;
                } else {
                    $io->warning("Shipping company '{$data['shipping_company']}' not found for vessel '{$data['name']}'");
                }
            }
        }

        $io->success("Imported $count vessels");
    }

    private function importTrips($spreadsheet, SymfonyStyle $io): void
    {
        $io->section('Importing Trips');

        $sheet = $spreadsheet->getSheetByName('trip');
        if (!$sheet) {
            $io->warning('Sheet "trip" not found');
            return;
        }

        $rows = $sheet->toArray();
        $headers = array_shift($rows);

        $count = 0;
        foreach ($rows as $row) {
            $data = array_combine($headers, $row);

            // Finde das zugehörige Vessel
            $vessel = $this->entityManager->getRepository(Vessel::class)
                ->findOneBy(['name' => $data['vessel']]);

            if (!$vessel) {
                $io->warning("Vessel '{$data['vessel']}' not found for trip ID {$data['id']}");
                continue;
            }

            // Finde die Start-Location
            $startLocation = $this->entityManager->getRepository(Location::class)
                ->findOneBy(['name' => $data['start_location']]);

            if (!$startLocation) {
                $io->warning("Start location '{$data['start_location']}' not found for trip ID {$data['id']}");
                continue;
            }

            // Finde die End-Location
            $endLocation = $this->entityManager->getRepository(Location::class)
                ->findOneBy(['name' => $data['end_location']]);

            if (!$endLocation) {
                $io->warning("End location '{$data['end_location']}' not found for trip ID {$data['id']}");
                continue;
            }

            // Konvertiere Excel-Dates und kombiniere mit Zeit
            if (is_numeric($data['start_date'])) {
                $startDate = Date::excelToDateTimeObject($data['start_date']);
            } else {
                $startDate = new \DateTime($data['start_date']);
            }

            if (is_numeric($data['start_time'])) {
                $startTime = Date::excelToDateTimeObject($data['start_time']);
            } else {
                $startTime = new \DateTime($data['start_time']);
            }

            // Kombiniere Datum und Zeit für Start
            $startDate->setTime(
                (int)$startTime->format('H'),
                (int)$startTime->format('i'),
                (int)$startTime->format('s')
            );
            $startDateImmutable = DateTimeImmutable::createFromMutable($startDate);

            // Konvertiere Excel-Dates und kombiniere mit Zeit für Ende
            if (is_numeric($data['end_date'])) {
                $endDate = Date::excelToDateTimeObject($data['end_date']);
            } else {
                $endDate = new \DateTime($data['end_date']);
            }

            if (is_numeric($data['end_time'])) {
                $endTime = Date::excelToDateTimeObject($data['end_time']);
            } else {
                $endTime = new \DateTime($data['end_time']);
            }

            // Kombiniere Datum und Zeit für Ende
            $endDate->setTime(
                (int)$endTime->format('H'),
                (int)$endTime->format('i'),
                (int)$endTime->format('s')
            );
            $endDateImmutable = DateTimeImmutable::createFromMutable($endDate);

            // Prüfe, ob Trip bereits existiert (basierend auf Vessel und Datum)
            $existingTrip = $this->entityManager->getRepository(Trip::class)
                ->findOneBy([
                    'vessel' => $vessel,
                    'startDate' => $startDateImmutable,
                    'startLocation' => $startLocation
                ]);

            if (!$existingTrip) {
                $trip = new Trip($vessel, $startLocation, $endLocation, $startDateImmutable, $endDateImmutable);
                $trip->setCompleted();
                $this->entityManager->persist($trip);
                $count++;
            }
        }

        $io->success("Imported $count trips");
    }
}