<?php

namespace vonRotenberg\WeinanlieferungBundle\EventListener;

use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
use Contao\CoreBundle\Monolog\ContaoContext;
use Contao\MemberModel;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Filesystem\Filesystem;
use vonRotenberg\WeinanlieferungBundle\Event\CheckInCompletedEvent;
use vonRotenberg\WeinanlieferungBundle\Model\WeinanlieferungLageModel;
use vonRotenberg\WeinanlieferungBundle\Model\WeinanlieferungLeseartModel;
use vonRotenberg\WeinanlieferungBundle\Model\WeinanlieferungRebsorteModel;

/**
 * Listener for the CheckInCompletedEvent.
 * Generates a CSV export file for each checked-in booking.
 */
class CheckInCompletedListener implements EventSubscriberInterface
{
    /**
     * @var LoggerInterface
     */
    private $logger;

    /**
     * @var string
     */
    private $projectDir;

    /**
     * Constructor.
     *
     * @param LoggerInterface $logger
     * @param string $projectDir
     */
    public function __construct(LoggerInterface $logger, string $projectDir)
    {
        $this->logger = $logger;
        $this->projectDir = $projectDir;
    }

    /**
     * Returns an array of event names this subscriber wants to listen to.
     *
     * @return array The event names to listen to
     */
    public static function getSubscribedEvents()
    {
        return [
            CheckInCompletedEvent::NAME => 'onCheckInCompleted',
        ];
    }

    /**
     * Handle the check-in completed event.
     *
     * @param CheckInCompletedEvent $event
     */
    public function onCheckInCompleted(CheckInCompletedEvent $event)
    {
        // Get the reservation data from the event
        $reservationData = $event->getReservationData();
        $reservationModel = $event->getReservationModel();

        // Log the event for testing purposes
        $this->logger->log(
            LogLevel::INFO,
            sprintf('Check-in completed for reservation ID: %s', $reservationData['id']),
            ['contao' => new ContaoContext(__METHOD__, 'CHECK_IN')]
        );

        // Generate and save the CSV export
        $this->generateCsvExport($reservationData, $reservationModel);
    }

    /**
     * Generate and save the CSV export file.
     *
     * @param array $reservationData
     * @param object $reservationModel
     */
    private function generateCsvExport(array $reservationData, $reservationModel)
    {
        // Create export directory if it doesn't exist
        $exportDir = $this->projectDir . '/export/check_in';
        $filesystem = new Filesystem();

        if (!$filesystem->exists($exportDir)) {
            $filesystem->mkdir($exportDir, 0755);
        }

        // Get member data
        $memberId = $reservationData['uid'];
        $memberModel = MemberModel::findById($memberId);

        if (null === $memberModel) {
            $this->logger->log(
                LogLevel::ERROR,
                sprintf('Could not find member with ID: %s', $memberId),
                ['contao' => new ContaoContext(__METHOD__, 'CHECK_IN_CSV_EXPORT')]
            );
            return;
        }

        // Get behaelter numbers
        $behaelterNumbers = json_decode($reservationData['behaelter_numbers'], true);
        if (!is_array($behaelterNumbers) || empty($behaelterNumbers)) {
            $this->logger->log(
                LogLevel::ERROR,
                sprintf('No behaelter numbers found for reservation ID: %s', $reservationData['id']),
                ['contao' => new ContaoContext(__METHOD__, 'CHECK_IN_CSV_EXPORT')]
            );
            return;
        }

        // Check if we have the new format (array of objects with behaelter and member)
        // or the old format (simple array of behaelter numbers)
        $isNewFormat = isset($behaelterNumbers[0]) && is_array($behaelterNumbers[0]) && isset($behaelterNumbers[0]['behaelter']);

        // If it's the old format, convert it to the new format for compatibility
        if (!$isNewFormat) {
            $oldFormat = $behaelterNumbers;
            $behaelterNumbers = [];
            foreach ($oldFormat as $number) {
                $behaelterNumbers[] = [
                    'behaelter' => $number,
                    'member' => $memberModel->memberno
                ];
            }
        }

        // Format check-in date
        $checkInDate = date('d.m.Y', $reservationData['checked_in_on']);

        // Get sorten (grape varieties and harvest types)
        $sortenData = [];
        $sortenLeseartPairs = explode(';', $reservationData['sorten']);
        foreach ($sortenLeseartPairs as $pair) {
            if (empty($pair)) {
                continue;
            }

            list($sorteId, $leseartId) = explode(',', $pair);

            $rebsorteModel = WeinanlieferungRebsorteModel::findById($sorteId);
            $leseartModel = WeinanlieferungLeseartModel::findById($leseartId);

            if (null !== $rebsorteModel && null !== $leseartModel) {
                $sortenData[] = [
                    'rebsorte_id' => $rebsorteModel->ident_string,
                    'rebsorte_title' => $rebsorteModel->title,
                    'leseart_id' => $leseartModel->ident_string,
                    'leseart_title' => $leseartModel->title
                ];
            }
        }

        // Get lagen (locations)
        $lagenData = [];
        $lagenIds = explode(',', $reservationData['lage']);
        foreach ($lagenIds as $lageId) {
            if (empty($lageId)) {
                continue;
            }

            $lageModel = WeinanlieferungLageModel::findById($lageId);

            if (null !== $lageModel) {
                $lagenData[] = [
                    'lage_id' => $lageModel->ident_string,
                    'lage_title' => $lageModel->title
                ];
            }
        }

        // Get ernteart (harvest method)
        $ernteartValues = explode(',', $reservationData['ernteart']);
        $ernteartMapping = [
            'handlese' => 'H',
            'vollernter' => 'V'
        ];

        // Group CSV data by member number
        $csvDataByMember = [];
        $memberNames = []; // Store member names for logging

        // For each behaelter, create a line in the CSV and group by member number
        foreach ($behaelterNumbers as $behaelterData) {
            // Get behaelter number and member number from the data
            $behaelterNumber = $isNewFormat ? $behaelterData['behaelter'] : $behaelterData;
            $memberNo = $isNewFormat && isset($behaelterData['member']) ? $behaelterData['member'] : $memberModel->memberno;

            // Skip special value 9999 if needed
            /*if ($behaelterNumber === '9999') {
                continue;
            }*/

            // If member number is empty, use the booking member's number
            if (empty($memberNo)) {
                $memberNo = $memberModel->memberno;
            }

            // Get member name - use the booking member's name as default
            $memberName = $memberModel->firstname . ' ' . $memberModel->lastname;

            // If the member number is different from the booking member's number,
            // try to find the corresponding member to get their name
            if ($memberNo !== $memberModel->memberno) {
                $otherMember = MemberModel::findByMemberno($memberNo);
                if ($otherMember) {
                    $memberName = $otherMember->firstname . ' ' . $otherMember->lastname;
                }
            }

            // Store member name for logging
            $memberNames[$memberNo] = $memberName;

            // Use the first sorte, leseart, and lage if available
            $rebsorteId = !empty($sortenData) ? $sortenData[0]['rebsorte_id'] : '';
            $rebsorteTitle = !empty($sortenData) ? $sortenData[0]['rebsorte_title'] : '';
            $leseartId = !empty($sortenData) ? $sortenData[0]['leseart_id'] : '';
            $leseartTitle = !empty($sortenData) ? $sortenData[0]['leseart_title'] : '';
            $lageId = !empty($lagenData) ? $lagenData[0]['lage_id'] : '';
            $lageTitle = !empty($lagenData) ? $lagenData[0]['lage_title'] : '';

            // Map ernteart values to H/V
            $ernteart = '';
            foreach ($ernteartValues as $value) {
                if (isset($ernteartMapping[$value])) {
                    $ernteart = $ernteartMapping[$value];
                    break;
                }
            }

            // Create CSV line and add to the appropriate member group
            if (!isset($csvDataByMember[$memberNo])) {
                $csvDataByMember[$memberNo] = [];
            }

            $csvDataByMember[$memberNo][] = [
                $memberNo, // member id (now using the member number associated with this behaelter)
                $memberName, // member first and lastname
                $rebsorteId, // rebsorte identifikator
                $rebsorteTitle, // rebsorte title
                $lageId, // lage identifikator
                $lageTitle, // lage title
                $leseartId, // leseart identifikator
                $leseartTitle, // leseart title
                $ernteart, // ernteart (H for handlese, V for vollernter)
                $behaelterNumber, // behaelter number
                $checkInDate, // check-in date
//                $reservationData['behaelter'] // behaelter amount for the whole checked-in booking
            ];
        }

        // Generate a separate CSV file for each member
        $generatedFiles = [];
        foreach ($csvDataByMember as $memberNo => $csvData) {
            // Generate CSV file with the naming scheme "bookingId_memberno.csv"
            $filename = $reservationData['id'] . '_' . $memberNo . '.csv';
            $filepath = $exportDir . '/' . $filename;
            $generatedFiles[] = $filepath;

            $file = fopen($filepath, 'w');

            foreach ($csvData as $line) {
                $line[] = count($csvData);
                fputcsv($file, $line, ';');
            }

            fclose($file);

            $this->logger->log(
                LogLevel::INFO,
                sprintf('CSV export created for reservation ID: %s, member: %s (%s) at %s',
                    $reservationData['id'],
                    $memberNo,
                    $memberNames[$memberNo],
                    $filepath
                ),
                ['contao' => new ContaoContext(__METHOD__, 'CHECK_IN_CSV_EXPORT')]
            );
        }

        // Log summary of all generated files
        $this->logger->log(
            LogLevel::INFO,
            sprintf('CSV export completed for reservation ID: %s. Generated %d file(s) for %d member(s).',
                $reservationData['id'],
                count($generatedFiles),
                count($csvDataByMember)
            ),
            ['contao' => new ContaoContext(__METHOD__, 'CHECK_IN_CSV_EXPORT')]
        );
    }
}