<?php

namespace Velis\Bpm\Workflow\Handler;

use Exception;
use Psr\SimpleCache\InvalidArgumentException;
use Ticket\Ticket;
use Velis\App;
use Velis\Arrays;
use Velis\Bpm\Ticket\Log;
use Velis\Bpm\Ticket\Post;
use Velis\Bpm\Workflow\Handler;
use Velis\Label;

/**
 * Ticket overwrite workflow handler
 * @author Olek Procki <olo@velis.pl>
 */
class TicketAppend extends Handler
{
    /**
     * Handler execution method
     *
     * @param \Velis\Bpm\Ticket\Ticket $subject
     * @param mixed $additionalData
     * @throws InvalidArgumentException
     */
    public function run($subject, $additionalData)
    {
        $originalData = $subject->getArrayCopy();
        $modifiedData = $this->getArrayCopy();
        $commit       = false;

        $subject->append(
            Arrays::filterKeepZeros(
                $modifiedData
            )
        );

        $isResponsibleChanged = false;

        if ($modifiedData['responsible_department_id']) {
            $subject['responsible_user_id'] = null;
            $isResponsibleChanged = true;
        }

        if ($modifiedData['responsible_user_id']) {
            $subject['responsible_department_id'] = null;
            $isResponsibleChanged = true;
        }

        try {
            if ($this->_workflow->isInvokedAfterEvent()) {
                if (!App::$user->id()) {
                    $this->error($subject, $additionalData, 'User is not logged');
                    return;
                }
                $commit = self::$_db->startTrans();

                $subject->sanitize();
                $subject->modify(true, true);
                $subject->unstash();

                if (is_array($additionalData) && $additionalData['post'] instanceof Post) {
                    $post = $additionalData['post'];
                } elseif ($additionalData instanceof Post) {
                    $post = $additionalData;
                }
                if (!$post['ticket_post_id']) {
                    $post = new Post([
                        'ticket_id' => $subject->id(),
                        'user_id'   => App::$user->id(),
                        'person_id' => App::$user->id(),
                        'ticket_post_visibility_id' => Post::TYPE_PROTECTED
                    ]);
                    $post->add(true);
                }

                $label = null;
                if ($additionalData instanceof Label) {
                    $label = $additionalData;
                } elseif (is_array($additionalData) && $additionalData['label'] instanceof Label) {
                    $label = $additionalData['label'];
                }

                $log = Log::factory($subject, $post);
                $log['ticket_post_id']       = $post->id();
                $log['ticket_log_action_id'] = $isResponsibleChanged ? Log::DELEGATE : Log::EDIT;

                if ($label) {
                    $event = $this->_workflow->getEvent();
                    if ($event->id() == 'TicketLabelAdded') {
                        $log->addLabel($label->id());
                    } elseif ($event->id() == 'TicketLabelRemoved') {
                        $log->removeLabel($label->id());
                    }
                }

                $changes = $subject->getDiff();

                if ($changes || $log->hasLabels()) {
                    if ($log->hasLabels()) {
                        $changes = array_merge($changes, $log->labelLog());
                    }
                    $log['description'] = '* ' . implode("\n* ", array_filter($changes));
                    $log->add(true);
                    $log->notify();
                }

                if ($commit) {
                    self::$_db->commit();
                }
            }
            $this->success(
                $subject,
                $originalData
            );
        } catch (Exception $e) {
            if ($commit) {
                self::$_db->rollback();
            }
            $this->error($subject, $additionalData, $e);
        }
    }


    /**
     * Returns parameters reflection info
     * @return array
     */
    public static function getParamsReflection()
    {
        $ticketConditions = Ticket::getWorkflowReflection();

        return Arrays::extractFields(
            $ticketConditions,
            [
                'ticket_category_id',
                'ticket_classification_id',
                'ticket_status_id',
                'ticket_priority_id',
                'responsible_user_id',
                'responsible_department_id',
                'ticket_acceptance_workflow_id',
            ]
        );
    }
}
