<?php
/**
 * @author Ulrich Hecht <ulrich.hecht@hecht-software.de>
 * @date 02/13/2017
 */

namespace AppBundle\Export;


use AppBundle\Entity\BookingRequest;
use AppBundle\Entity\TravelDate;
use AppBundle\Entity\Traveler;
use AppBundle\Util;
use Monolog\Logger;

class BookingSternToursCrmExporter extends SternToursCrmExporter
{

    public function __construct(Logger $logger)
    {
        parent::__construct($logger);
    }

    public function process(BookingRequest $bookingRequest, TravelDate $travelDate, $bookingPriceInfo)
    {
        $tp = $travelDate->getTravelProgram();
        $startDateStr = $travelDate->getStart()->format('Y-m-d');
        $lead = $this->createLead($bookingRequest, $travelDate);
        if ($lead === null)
        {
            $this->warn('Failed creating lead in CRM Lead', $bookingRequest, $travelDate, Logger::ERROR);
            return false;
        }
        $bookingUrl = $this->createBooking($bookingRequest, $travelDate, $bookingPriceInfo, $lead['customer_id'], $lead['id']);
        if ($bookingUrl === false)
        {
            $this->warn('Failed creating booking in CRM Booking', $bookingRequest, $travelDate, Logger::ERROR);
            return false;
        }

        for ($i = 1; $i < $bookingRequest->getTravelerCount(); ++$i)
        {
            if (!$this->createTraveler($bookingUrl, $bookingRequest->getTravelers()[$i]))
            {
                $this->warn('Failed creating traveler with index '. $i .' in CRM.', $bookingRequest, $travelDate);
            }
        }

        if ($tp->getIsMediated())
        {
            $serviceItemDefaults = [
                'travel_company_id' => $tp->getOrganizer()->getCmsId(),
                'travel_date' => $startDateStr,
                'commission' => 0,
            ];

            foreach ($bookingPriceInfo['rooms'] as $room)
            {
                $this->createServiceItem($bookingUrl, $serviceItemDefaults + [
                    'service_price' => $room['price_total'],
                    'name' => $room['name'],
                ]);
            }

            $this->createServiceItem($bookingUrl, $serviceItemDefaults + [
                'service_price' => $bookingRequest->getTravelerCount() * $bookingPriceInfo['departure']->getExtraCharge(),
                'name' => $bookingRequest->getTravelerCount() .' x '. $bookingPriceInfo['departure']->getName()
            ]);

            foreach ($bookingRequest->getTravelOptions() as $option)
            {
                $this->createServiceItem($bookingUrl, $serviceItemDefaults + [
                    'service_price' => $option->getPrice() * $bookingRequest->getTravelerCount(),
                    'name' => $bookingRequest->getTravelerCount() .' x '. $option->getName()
                ]);
            }

            // Actually: extra_category
            foreach ($bookingPriceInfo['classOptions'] as $classOption)
            {
                $this->createServiceItem($bookingUrl, $serviceItemDefaults + [
                    'service_price' => $classOption['count'] * $classOption['price'],
                    'name' => $classOption['count'] .' x '. $classOption['name']
                ]);
            }
        }
        else
        {
            $viewPosition = 100;
            $viewPositionPrice = 50;
            $endDateStr = $travelDate->getEnd()->format('Y-m-d');

            $arrangementDefaults = [
                'state' => (new \DateTime())->format('Y-m-d'),
                'in_pdf' => 1
            ];

            $this->createArrangement($bookingUrl, $arrangementDefaults + [
                'type_id' => 4, // Flug
                'type_s' => 'Flug',
                'begin' => $startDateStr,
                'view_position' => --$viewPosition,
                'data_s' => ['Hinflug' => 'von '. $bookingPriceInfo['departure']->getName()],
            ]);

            $this->createArrangement($bookingUrl, $arrangementDefaults + [
                'type_id' => 26, // Preisinformation
                'type_s' => 'Preisinformation',
                'view_position' => --$viewPositionPrice,
                'data_s' => [
                    'Name' => 'Abfahrts-/Abflugort '. $bookingPriceInfo['departure']->getName(),
                    'Preis' => $bookingPriceInfo['departure']->getExtraCharge(),
                    'Teilnehmer' => $bookingRequest->getTravelerCount(),
                ],
            ]);

            $this->createArrangement($bookingUrl, $arrangementDefaults + [
                'type_id' => 24, // Rundreise
                'type_s' => 'Rundreise', // Rundreise
                'begin' => $startDateStr,
                'end' => $endDateStr,
                'view_position' => --$viewPosition,
                'data_s' => ['Name' => $tp->getTitle() .' ('. $travelDate->getName() .')'],
            ]);

            $roomStrs = [];
            foreach ($bookingPriceInfo['rooms'] as $room)
            {
                $roomStrs[] = '1x '. $room['name'];

                $this->createArrangement($bookingUrl, $arrangementDefaults + [
                    'type_id' => 26, // Preisinformation
                    'type_s' => 'Preisinformation',
                    'view_position' => --$viewPositionPrice,
                    'data_s' => [
                        'Name' => 'pro Person im \''. $room['name'] .'\'',
                        'Preis' => $room['price'],
                        'Teilnehmer' => $room['adults'],
                    ],
                ]);
            }
            $this->createArrangement($bookingUrl, $arrangementDefaults + [
                'type_id' => 5, // Hotel
                'type_s' => 'Hotel',
                'begin' => $startDateStr,
                'end' => $endDateStr,
                'view_position' => --$viewPosition,
                'data_s' => ['Zimmer' => implode(', ', $roomStrs)],
            ]);

            // Actually: extra_category
            foreach ($bookingPriceInfo['classOptions'] as $classOption)
            {
                $this->createArrangement($bookingUrl, $arrangementDefaults + [
                    'type_id' => 26, // Preisinformation
                    'type_s' => 'Preisinformation',
                    'view_position' => --$viewPositionPrice,
                    'data_s' => [
                        'Name' => $classOption['name'],
                        'Preis' => $classOption['price'],
                        'Teilnehmer' => $classOption['count'],
                    ],
                ]);
            }

            $this->createArrangement($bookingUrl, $arrangementDefaults + [
                'type_id' => 4, // Flug
                'type_s' => 'Flug',
                'begin' => $endDateStr,
                'view_position' => --$viewPosition,
                'data_s' => ['Rückflug' => $bookingRequest->getDeparture()->getName()],
            ]);

            foreach ($bookingRequest->getTravelOptions() as $option)
            {
                $this->createArrangement($bookingUrl, $arrangementDefaults + [
                    'type_id' => 26, // Preisinformation
                    'type_s' => 'Preisinformation',
                    'view_position' => --$viewPositionPrice,
                    'data_s' => [
                        'Name' => $option->getName(),
                        'Preis' => $option->getPrice(),
                        'Teilnehmer' => $bookingRequest->getTravelerCount(),
                    ],
                ]);
            }
        }

        foreach ($bookingPriceInfo['insurances'] as $insuranceInfo)
        {
            $this->createServiceItem($bookingUrl, [
                'travel_company_id' => 30,
                'service_price' => $insuranceInfo['count'] * $insuranceInfo['insurancePriceValue'],
                'name' => $insuranceInfo['count'] . 'x ' . $insuranceInfo['insurance']->getName() . ' ('.
                    $insuranceInfo['insurancePrice']->getCode() . ')',
                'commission' => round(($insuranceInfo['count'] * $insuranceInfo['insurancePriceValue']) * 20 / 100, 2),
                'travel_date' => $startDateStr,
            ]);
        }

        return $bookingUrl;
    }

    private function createLead(BookingRequest $bookingRequest, TravelDate $travelDate)
    {
        $resp = $this->httpPost('lead', ['lead' => [
            'customerForm' => [
                'salutation_id' => $bookingRequest->getSalutation(),
                'name' => $bookingRequest->getLastName(),
                'firstname' => $bookingRequest->getFirstName(),
                'street' => $bookingRequest->getStreetAddress(),
                'zip' => $bookingRequest->getZipCode(),
                'city' => $bookingRequest->getCity(),
                'country_id' => $bookingRequest->getNation(),
                'phone' => $bookingRequest->getPhone(),
                'fax' => $bookingRequest->getFax(),
                'email' => $bookingRequest->getEmail()
            ],
            'request_date' => (new \DateTime())->format('Y-m-d'),
            'sf_guard_user_id' => self::API_USER_ID,
            'status_id' => 7, // 'gebucht'
            'travelperiod_start' => $travelDate->getStart()->format('Y-m-d'),
            'travelperiod_end' => $travelDate->getEnd()->format('Y-m-d'),
            //'travelcategory_id'
            'is_closed' => 1,
            'website_id' => self::WEBSITE_ID,
            'initialcontacttype_id' => 14,
            // 'travelperiod_length
            'remarks' => $bookingRequest->getNotes()
        ]]);

        if ($resp['success'])
        {
            $ret = $this->httpGet($resp['location']);
            if ($ret == null)
            {
                $this->warn('Failed retrieving newly created lead object', $bookingRequest, $travelDate);
            }
            return $ret;
        }
        return null;
    }

    private function createBooking(BookingRequest $bookingRequest, TravelDate $travelDate, $bookingPriceInfo,
        $customerId, $leadId)
    {
        $tp = $travelDate->getTravelProgram();
        $resp = $this->httpPost('booking', ['booking' => [
            'booking_date' => (new \DateTime())->format('Y-m-d'),
            'customer_id' => $customerId,
            'lead_id' => $leadId,
            'travel_country_id' => $tp->getTravelCountry(),
            'travel_category_id' => $tp->getTravelCategory(),
            'travelagenda_id' => $tp->getTravelAgenda(),
            'sf_guard_user_id' => self::API_USER_ID,
            'branch_id' => 4,
            'website_id' => self::WEBSITE_ID,
            'title' => $tp->getTitle(),
            'start_date' => $travelDate->getStart()->format('Y-m-d'),
            'end_date' => $travelDate->getEnd()->format('Y-m-d'),
            'pax' => $bookingRequest->getTravelerCount(),
            'travel_number' => $travelDate->getName(),
            'price' => $bookingPriceInfo['totalWithoutInsurance'],

            'participant_salutation_id' => $bookingRequest->getTravelers()[0]->getSex(),
            'participant_name' => $bookingRequest->getTravelers()[0]->getLastName(),
            'participant_firstname' => $bookingRequest->getTravelers()[0]->getFirstName(),
            'participant_birthdate' => $bookingRequest->getTravelers()[0]->getBirthDate(),
        ]]);
        if (!$resp['success'])
        {
            return false;
        }
        return $resp['location'];
    }

    private function createTraveler($bookingUrl, Traveler $traveler)
    {
        $resp = $this->httpPost($bookingUrl .'/participant.json', ['participant' => [
            'participant_salutation_id' => $traveler->getSex(),
            'participant_name' => $traveler->getLastName(),
            'participant_firstname' => $traveler->getFirstName(),
            'participant_birthdate' => $traveler->getBirthDate(),
        ]], true);
        return $resp['success'];
    }

    private function createServiceItem($bookingUrl, $serviceItemData)
    {
        $resp = $this->httpPost($bookingUrl .'/serviceitem.json', ['booking_service_item' => $serviceItemData], true);
        if (!$resp['success'])
        {
            $this->warn('Failed creating service item '. $serviceItemData['name'] .' for booking '. $bookingUrl);
        }
        return $resp['success'];
    }

    private function createArrangement($bookingUrl, $arrangementData)
    {
        if (isset($arrangementData['data_s']) && is_array($arrangementData['data_s']))
        {
            $tmp = [];
            foreach ($arrangementData['data_s'] as $k => $v)
            {
                $tmp[] .= $k .': '. $v;
            }
            $arrangementData['data_s'] = implode("\n", $tmp);
        }
        $resp = $this->httpPost($bookingUrl .'/arrangement.json', ['arrangement' => $arrangementData], true);
        if (!$resp['success'])
        {
            $this->warn('Failed creating arrangement item '. $arrangementData['type_s'] .' for booking '. $bookingUrl);
        }
        return $resp['success'];
    }

    private function warn($msg, BookingRequest $bookingRequest = null, TravelDate $travelDate = null,
        $level = Logger::WARNING)
    {
        $this->logger->log($level, 'SternToursCrmBookingExporter: '. $msg);
        $this->logger->log($level, '*** Date: '. (new \DateTime())->format('d.m.Y'));
        if ($travelDate !== null)
        {
            $this->logger->log($level, '*** Travel date: '. $travelDate->getName() .'('. $travelDate->getStart()->format('d.m.Y') .
                ' - '. $travelDate->getEnd()->format('d.m.Y') .')');
            //$this->logger->warn('*** Travel program ID: '. $travelDate->)
        }
        if ($bookingRequest !== null)
        {
            $this->logger->log($level, '*** User name: '. $bookingRequest->getFirstName() .' '. $bookingRequest->getLastName());
        }
    }
}