<?php
/**
 * @package    Proxim
 * @author     Mike Kivu <mikepaul620@gmail.com | https://webexpert.co.ke>
 * @copyright  2019 Proxim
 * @version    1.5.0
 * @since      File available since Release 1.0.0
 */

namespace Proxim\Api;

use Db;
use Proxim\Database\DbQuery;
use Proxim\Controller;
use Proxim\Mail;
use Proxim\Validate;
use Proxim\Tools;
use Proxim\Site\Site;
use Proxim\Pager;
use Proxim\Notification;
use Proxim\PriceCalculator;
use Proxim\Configuration;
use Proxim\Hook;
use Proxim\User\Customer;
use Proxim\User\Employee;
use Proxim\Order\Order;
use Proxim\Order\Message;
use Proxim\Order\Bid;
use Proxim\Order\AdditionalService;
use Proxim\Order\Revision;
use Proxim\Order\File;
use Proxim\Order\Rating;
use Proxim\Preference\Deadline;
use Proxim\Preference\Discipline;
use Proxim\Preference\PaperFormat;
use Proxim\Preference\PaperType;
use Proxim\Preference\UploadType;
use Proxim\Util\DateUtils;
use Proxim\Util\ArrayUtils;
use Proxim\Util\StringUtils;

class Orders extends Controller {

    public function createOrder(){
        global $globals;
        $app = $this->app;
        $payload = $app->request->post();
        $user = $app->container->user;

        $new_order = true;
        if(ArrayUtils::has($payload, 'order_id')) {
            $order_id = ArrayUtils::get($payload, 'order_id');
            $order = new Order( (int) $order_id );
            if(!Validate::isLoadedObject($order)) {
                return $this->response([
                    'error' => true,
                    'message' => "This order does not exist"
                ]);
            }
            $new_order = false;
        } else {
            $order = new Order();
            $order->service_type = Order::COMPLEX_ASSIGNMENT;
        }

        $changeDeadline = ArrayUtils::has($payload, 'changeDeadline');

        $toptitle = ArrayUtils::get($payload, 'topic');
        if (!$toptitle) {
			return $this->response([
                "error" => true,
                "message" => "Enter the title for your order"
            ]);
        }

        $tracking_id = ArrayUtils::get($payload, 'tracking_id');
        if($tracking_id && Tools::strlen($tracking_id) < 3) {
            return $this->response([
                "error" => true,
                "message" => "The tracking ID must be at least 3 characters long. Please try another"
            ]);
        }

        /** Writer Category */
        $writer_cat_id = (int) ArrayUtils::get($payload, 'writerCategoryId'); 
        $writerPreferences = ArrayUtils::get($globals, 'writerPreferences');

        $writer_percent = 0;
        if (ArrayUtils::has($writerPreferences, $writer_cat_id)) {
            $writer_preference = ArrayUtils::get($writerPreferences, $writer_cat_id);
            $writer_percent = ArrayUtils::has($writer_preference, 'percent') ? (int) ArrayUtils::get($writer_preference, 'percent') : 0;
        }

        /** Pages / Charts / Slides */
        $charts = (int) ArrayUtils::get($payload, 'charts'); 
        $pages = (int) ArrayUtils::get($payload, 'pages'); 
        $slides = (int) ArrayUtils::get($payload, 'slides');
        $min_sources = (int) ArrayUtils::get($payload, 'sources');

        // @todo both pages, charts, and slides can't be zero
		if ( $pages == 0 && $slides == 0 && $charts == 0) {
			return $this->response([
                "error" => true,
                "message" => "You need to order at least 1 page or 1 slide or 1 chart"
            ]);
        }
        
        /** Spacing */
        $spacing = ArrayUtils::get($payload, 'spacing'); 
        if ( !$spacing || !in_array($spacing, array(Order::SPACING_SINGLE, Order::SPACING_DOUBLE)) ) {
			return $this->response([
                "error" => true,
            ]);
        }

        /** Topic category */
        $topic_cat_id = (int) ArrayUtils::get($payload, 'topicCatId');
        $discipline = new Discipline( $topic_cat_id );
        if(Validate::isLoadedObject($discipline)) {
            $topic_cat_option = $discipline->title;
			$isComplexAssignment = $discipline->is_complex_assignment;
        } else {
            // other
            $topic_cat_id == 52;
            $topic_cat_option = ArrayUtils::get($payload, 'topcatOption');
			$isComplexAssignment = 1;
        }
        
        /** Paper Type */
        $paper_type_id = (int) ArrayUtils::get($payload, 'paperTypeId');
        $paperType = new PaperType( $paper_type_id );
        if(Validate::isLoadedObject($paperType)) {
            $paper_type_option = $paperType->title;
        } else {
            $paper_type_id == 64;
            $paper_type_option = ArrayUtils::get($payload, 'paperTypeOption');
        }

        /** Paper Format */
        $paper_format_id = (int) ArrayUtils::get($payload, 'paperFormat');

        $paperFormat = new PaperFormat( $paper_format_id  );
        if(Validate::isLoadedObject($paperFormat)) {
            $paper_format_option = $paperFormat->title;
        } else {
            $paper_format_id = 4;
            $paper_format_option = ArrayUtils::get($payload, 'paperFormatOption');
        }
        
        if($new_order || $changeDeadline) {
            $tariff_id = (int) ArrayUtils::get($payload, 'tariffId');
            $deadline = new Deadline( (int) $tariff_id );
            if(!Validate::isLoadedObject($deadline)) {
                return $this->response([
                    "error" => true,
                    "message" => "Select a valid deadline",
                ]);
            }

            $order->tariff_id = $tariff_id;
            $order->price_per_page = $deadline->price_per_page;
            $order->hrs_customer = $deadline->hrs_customer;
            $order->hrs_writer = $deadline->hrs_writer;
            $order->customer_deadline = DateUtils::date(time() + ($deadline->hrs_customer*60*60));
            $order->writer_deadline = DateUtils::date(time() + ($deadline->hrs_writer*60*60));
        }

        $paper_details = ArrayUtils::get($payload, 'paperDetails');

        $used_sources = ArrayUtils::has($payload, 'usedsources') ? true : false;
        $writer_samples = ArrayUtils::has($payload, 'samplesNeeded') ? true : false;
        $progressive_delivery = ArrayUtils::has($payload, 'progressiveDeliveryHidden') ? true : false;
        $expert_proofreading = ArrayUtils::has($payload, 'expertProofreading') ? true : false;

        if(ArrayUtils::has($payload, 'academicLevelId')) {
            $academic_level_id = ArrayUtils::get($payload, 'academicLevelId');
            $order->academic_level_id = $academic_level_id;
        }

        if(ArrayUtils::has($payload, 'customerId')) {
            $customerId = ArrayUtils::get($payload, 'customerId');

            $customer = new Customer( (int) $customerId );
            if(!Validate::isLoadedObject($customer)) {
                return $this->response([
                    "error" => true,
                    "message" => "Customer <strong>#$customerId</strong> does not exist",
                ]);
            }

            $order->customer_id = $customer->id;
            $order->site_id = $customer->site_id;
        } 

        $order->title = $toptitle;
        $order->tracking_id = $tracking_id;
        $order->paper_type_id = $paper_type_id;
        $order->paper_type_option = $paper_type_option;
        $order->topic_category_id = $topic_cat_id;
        $order->topic_category_option = $topic_cat_option;
        $order->is_complex_assignment = $isComplexAssignment;
        $order->paper_format_id = $paper_format_id;
        $order->paper_format_option = $paper_format_option;

        $order->writer_category_id = $writer_cat_id;
        $order->writer_percent = $writer_percent;

        $order->sources = $min_sources;
        $order->pages = $pages;
        $order->charts = $charts;
        $order->slides = $slides;
        $order->spacing = $spacing;
        $order->paper_details = $paper_details;

        /** Additional Services */
        $order->used_sources = $used_sources;
        $order->writer_samples = $writer_samples;
        $order->expert_proofreading = $expert_proofreading;
        $order->progressive_delivery = $progressive_delivery;

        $calc = $order->calculate();
        $baseCost = ArrayUtils::get($calc, 'rawCost');
        $servicesById = ArrayUtils::get($calc, 'servicesById');

        $order->raw_cost = $baseCost;
        $order->total = ArrayUtils::get($calc, 'totalCost'); 
        $order->writer_pay = ArrayUtils::get($calc, 'writerCost');
        $order->editor_pay = ArrayUtils::get($calc, 'editorCost');

        $serviceProvideSamples = $servicesById[PriceCalculator::SERVICES_IDS['PROVIDE_ME_SAMPLES']];
        if ($serviceProvideSamples['cost'] > 0) {
            $order->writer_samples = true;
        } else {
            $order->writer_samples = false;
        }

        $serviceUsedSources = $servicesById[PriceCalculator::SERVICES_IDS['USED_SOURCES']];
        if ($serviceUsedSources['cost'] > 0) {
            $order->used_sources = true;
        } else {
            $order->used_sources = false;
        }

        $serviceComplexAssignment = $servicesById[PriceCalculator::SERVICES_IDS['COMPLEX_ASSIGNMENT']];
        if ($serviceComplexAssignment['cost'] > 0) {
            $order->is_complex_assignment = true;
        } else {
            $order->is_complex_assignment = false;
        }

        $serviceExpertProofreading = $servicesById[PriceCalculator::SERVICES_IDS['EXPERT_PROOFREADING']];
        if ($serviceExpertProofreading['cost'] > 0) {
            $order->expert_proofreading = true;
        } else {
            $order->expert_proofreading = false;
        }

        $serviceProgressiveDelivery = $servicesById[PriceCalculator::SERVICES_IDS['PROGRESSIVE_DELIVERY']];
        if ($serviceProgressiveDelivery['cost'] > 0) {
            $order->progressive_delivery = true;
        } else {
            $order->progressive_delivery = false;
        }

        Hook::exec('actionOrderAdd', array('order_id' => (int) $order->id, 'order' => $order));

        if($new_order) {
            $order->add();

            return $this->response([
                'callback' => 'window.location.href="'.$app->base_uri.'/order/'.$order->id.'";'
            ]);	
        } else {
            $order->update();
            return $this->response([
                "success" => true,
                "message" => "Successfully updated"
            ]);
        }
    }

    public function order( $order_id, $do = null ) {
        $app = $this->app;
        $payload = $app->request->post();
        $params = $app->request->get();
        $user = $app->container->user;
        $smarty = $app->container->smarty;

        $order = new Order( (int) $order_id );
        if(!Validate::isLoadedObject($order)) {
            return $this->response([
                "error" => true,
                "message" => "This order does not exist"
            ]);
        }

        switch( $do ) {
            # mark order as paid
            case 'mark-as-paid':
                if (!$order->is_paid) {
                    $customerDeadline = time() + ($order->hrs_customer*60*60);
                    $writerDeadline = time() + ($order->hrs_writer*60*60);

                    if ($order->progressive_delivery) {
                        $order->status_id = Order::NEW_PAID;
                    } else {
                        $order->status_id = Order::ORDER_PUBLISHED;
                    }

                    $order->customer_deadline = DateUtils::date($customerDeadline);
                    $order->writer_deadline = DateUtils::date($writerDeadline);
                    $order->total_paid = $order->total;
                    $order->is_paid = 1;
                    $order->paid_at = DateUtils::now();
                    $order->update();
                }

                return $this->response([
                    'callback' => 'window.location.reload();'
                ]);
                break;
                
            # assign order
            case 'assign':
                $writer_id = (int) ArrayUtils::get($payload, 'uid');

                $writer = new Employee( $writer_id );
                if(!Validate::isLoadedObject($writer)) {
	                return $this->modal("ERROR", "Error", "The writer does not exist");
                }

                if(
                    $writer->cpp_type == "custom" &&
                    $writer->cpp_amount > 0
                ) {
                    Configuration::set('WRITER_CPP_TYPE', "fixed", PROX_SITE_ID);
                    Configuration::set('WRITER_AMOUNT_CPP', $writer->cpp_amount , PROX_SITE_ID);

                    $calc = $order->calculate();
                    $order->writer_pay = (float) ArrayUtils::get($calc, 'writerCost');
                    $order->update();
                }

                $order->status_id = Order::WRITER_ASSIGNED;
                $order->writer_id = $writer->id;
                $order->writer_assigned = 1;
                $order->writer_assigned_at = DateUtils::now();

                if(Configuration::get('CONFIRM_ORDER_ASSIGN')) {
                    $order->is_writer_confirmed = 0;
                } else {
                    $order->is_writer_confirmed = 1;
                }

                $order->update();

                $sql = new DbQuery();
                $sql->select('bid.bid_id');
                $sql->from('order_bid', 'bid');
                $sql->where('order_id = ' . (int) $order->id );
                $sql->where('writer_id = ' . (int) $writer->id );
                $bid_id = Db::getInstance(PROX_USE_SQL_SLAVE)->getValue( $sql );
                
                $bid = new Bid( (int) $bid_id );
                if( Validate::isLoadedObject($bid) ) {
                    $bid->is_assigned = 1;
                    $bid->update();
                }

                $smarty->assign([
                    'order_id' => $order->id,
                    'first_name' => $writer->first_name,
                    'last_name' => $writer->last_name,
                ]);
                
                $confirm_order_body = $smarty->fetch('messages/confirm_order.tpl');

                $message = new Message();
                $message->order_id = $order->id;
                $message->sender_id = Employee::START_ID;
                $message->from_department = DEPARTMENT_SUPPORT;
                $message->to_department = DEPARTMENT_WRITER;
                $message->subject = "Order #".$order->id.": Please confirm that you are working";
                $message->body = $confirm_order_body;
                $message->is_verified = 1;
                $message->verified_at = DateUtils::now();
                $success = $message->add();

                if(!$success) {
	                return $this->modal("ERROR", "Error", "Could not send the message");
                }

                try {
                    Mail::Send(
                        'order_assign',
                        $message->subject,
                        array(
                            'message' => Tools::nl2br($confirm_order_body)
                        ),
                        $writer->email
                    );
                } catch( \Exception $e ) {
			
                }

                return $this->response([
                    'callback' => 'window.location.reload();'
                ]);
                break;

            # take
            case 'take':

                if(!$user->is_editor) {
	                return $this->modal("ERROR", "Error", "You don't have the right permissions to do this");
                }
                
                if(!$order->editor_id && $order->editor_assigned) {
	                return $this->modal("ERROR", "Error", "This order has been assigned to another editor");
                }
                
                if ( $order->status_id == Order::DONE ) {
                    $order->editor_id = $user->id;
                    $order->editor_assigned = 1;
                    $order->editor_assigned_at = DateUtils::now();
                    $order->is_editor_confirmed = 1;
                    $order->update();
                    return $this->response([
                        'callback' => 'window.location.reload();'
                    ]);
                }

                break;

            # apply 
            case 'apply':
                if (
                    $order->status_id != Order::ORDER_PUBLISHED &&
                    $order->status_id != Order::WRITER_ACCEPTED
                ) {
                    return $this->response([
                        'callback' => 'window.location.reload();'
                    ]);
                }

                $bid = new Bid();
                $bid->order_id = $order->id;
                $bid->writer_id = $user->id;
                $bid->bid_time = (int) $order->hrs_writer*60*60;
                $bid->amount = $order->writer_pay;
                $bid->add();

                $order->status_id = Order::WRITER_ACCEPTED;
                $order->update();
                
                // notification
                $notification = new Notification();
                $notification->to_department = DEPARTMENT_SUPPORT;
                $notification->to_user_id = Employee::START_ID;
                $notification->from_department = DEPARTMENT_WRITER;
                $notification->from_user_id = $user->id;
                $notification->action = Notification::ACTION_ORDER;
                $notification->node_type = Notification::TYPE_BID_REQUEST;
                $notification->node_url = $order->id;
                $notification->send();

                return $this->response([
                    'callback' => 'window.location.reload();'
                ]);

                break;

            # remove bid
            case 'remove_bid':
                $bid_id = ArrayUtils::get($payload, 'bid_id');

                $bid = new Bid( (int) $bid_id );
                if( Validate::isLoadedObject($bid) ) {
                    $bid->delete();
                }

                return $this->response([
                    'callback' => 'window.location.reload();'
                ]);

                break;
            
            # confirm order
            case 'confirm':
                $do = ArrayUtils::get($payload, 'do');

                if ($do == "accept") {
                    $order->is_writer_confirmed = 1;
                    $order->update();

                    Db::getInstance()->update(
                        'order_bid', 
                        array(
                            'is_assigned' => 1
                        ),
                        'order_id = ' . (int) $order->id . ' AND writer_id = ' . (int) $user->id
                    );

                } elseif ( $do == "decline" ) {
                    $order->writer_id = null;
                    $order->status_id = Order::ORDER_PUBLISHED;
                    $order->update();
                    
                    # delete bid
                    Db::getInstance()->delete('order_bid', 'order_id = ' . (int) $order->id . ' AND writer_id = ' . (int) $user->id );
                }

                break;
                
            # complete order
            case 'complete':
                if ($user->is_writer) {
                    $order->status_id = Order::DONE;
                    $order->completed_at = DateUtils::now();
                    $order->update();

                    try {
                        $mailParams = array(
                            'order_id' => $order->id,
                            'site_name' => Configuration::get('SITE_NAME'),
                            'order_url' => $app->base_uri . '/order/' . $order->id
                        );

                        $receivers = array();
                        $receivers[] = Configuration::get('SITE_EMAIL');
                        $notification_emails = $app->getNotificationEmails();
                        array_merge($receivers, $notification_emails);
            
                        Mail::send(
                            'writer_submitted_order',
                            'Order #' . $order->id .  ' has been completed',
                            $mailParams,
                            $receivers
                        );  

                        $receivers = array();

                        $sql = new DbQuery();
                        $sql->select('e.email');
                        $sql->from('employee', 'e');
                        $sql->where('employee_group = ' . (int) Employee::GROUP_EDITOR);
                        $sql->where('is_started = 1');
                        $sql->where('is_banned = 0');
                        $result = Db::getInstance(PROX_USE_SQL_SLAVE)->executeS($sql);

                        foreach ($result as $editor) {
                            if( ArrayUtils::has($editor, 'email') && Validate::isEmail(ArrayUtils::get($editor, 'email')) ) {
                                $receivers[] = ArrayUtils::get($editor, 'email');
                            }
                        }

                        foreach ($receivers as $receiver) {
                            Mail::Send(
                                'editor_new_order',
                                'New Order #' . $order->id . ' available',
                                $mailParams,
                                $receiver
                            );
                        }
                    } catch( \Exception $e ) {
                    }
                }

                return $this->response([
                    'callback' => 'window.location.reload();'
                ]);
                break;  
                    
            # deliver order
            case 'deliver':
                $order->status_id = Order::DELIVERED;
                $order->finished_at = DateUtils::now();
                $order->delivered_at = DateUtils::now();
                $order->update();

                $customer = $order->getCustomer();
                
                $site = new Site( (int) $order->site_id );

                if(Validate::isLoadedObject($customer)) {
                    $order_files = $order->getFiles();

                    $file_attachments = array();

                    if(Configuration::get('ATTACH_COMPLETED_FILES')) {
                        foreach( $order_files as $file ) {
                            $file = new File( (int) $file['file_id']); 
                            if( Validate::isLoadedObject($file) ) {
                                if ( $file->uploader_id != $customer->id ) {
                                    $file_path = PROX_DIR_UPLOADS . $file->source;
        
                                    $mime_types = array(
                                        "htm" => "text/html",
                                        "exe" => "application/octet-stream",
                                        "zip" => "application/zip",
                                        "doc" => "application/msword",
                                        "docx" => "application/msword",
                                        "jpg" => "image/jpg",
                                        "php" => "text/plain",
                                        "xls" => "application/vnd.ms-excel",
                                        "ppt" => "application/vnd.ms-powerpoint",
                                        "gif" => "image/gif",
                                        "pdf" => "application/pdf",
                                        "txt" => "text/plain",
                                        "html"=> "text/html",
                                        "png" => "image/png",
                                        "jpeg"=> "image/jpg",
                                        "js" => "application/x-javascript"
                                    );
                                    
                                    if( array_key_exists($file->extension, $mime_types) ) {
                                        $mime_type = $mime_types[$file->extension];
                                    } else {
                                        $mime_type = "application/msword";
                                    }

                                    $file_name = $file->name;
                                    if($file->extension && !StringUtils::endsWith($file_name, $file->extension)) {
                                        $file_name .= "." . $file->extension;
                                    }
    
                                    $file_attachments[] = array(
                                        "name" => $file_name,
                                        "mime" => $mime_type,
                                        "content" => file_get_contents( $file_path ),
                                    );
                                }
                            } 
                        } 
                    }
                    
                    $smarty->assign([
                        'site_url' => $site->domain,
                        'order_id' => $order->id,
                        'name' => $customer->name,
                    ]);

                    $order_complete_body = $smarty->fetch('messages/order_complete.tpl');
    
                    $message = new Message();
                    $message->order_id = $order->id;
                    $message->sender_id = Employee::START_ID;
                    $message->from_department = DEPARTMENT_SUPPORT;
                    $message->to_department = DEPARTMENT_CUSTOMER;
                    $message->subject = "Please check the completed order";
                    $message->body = $order_complete_body;
                    $message->is_verified = 1;
                    $message->verified_at = DateUtils::now();
                    $success = $message->add();

                    try {
                        $mailParams = array(
                            'order_domain' => $site->domain,
                            'order_id' => $order->id,
                            'name' => $customer->name,
                        );

                        Mail::send(
                            'order_complete',
                            $message->subject,
                            $mailParams,
                            array(
                                $customer->email
                            ),
                            null,
                            null,
                            null,
                            $file_attachments,
                            null,
                            null,
                            null,
                            null,
                            null,
                            null,
                            $customer->site_id
                        );  
                    } catch( \Exception $e ) {
                        
                    }
                }
                
                return $this->response([
                    'callback' => 'window.location.reload();'
                ]);
                break;
                
            case 'pd_schedule':
                    
                $pages = (int) ArrayUtils::get($payload, 'pages');
                $charts = (int) ArrayUtils::get($payload, 'pages');
                $slides = (int) ArrayUtils::get($payload, 'pages');
                $customer_deadline = ArrayUtils::get($payload, 'pages');
                $writer_deadline = ArrayUtils::get($payload, 'pages');
                $comments = ArrayUtils::get($payload, 'pages');

                // @todo both pages, charts, and slides can't be zero
                if ( $pages == 0 && $slides == 0 && $charts == 0) {
                    return $this->response([
                        "error" => true,
                        "message" => "You need at least 1 page or 1 slide or 1 chart"
                    ]);
                }

                if(!Validate::isDate($customer_deadline)) {
                    return $this->response([
                        "error" => true,
                        "message" => "Please enter a vaild customer deadline"
                    ]);
                }

                if(!Validate::isDate($writer_deadline)) {
                    return $this->response([
                        "error" => true,
                        "message" => "Please enter a vaild writer deadline"
                    ]);                        
                }
                
                break;

            case 'edit-cost':

                if ( ArrayUtils::has($payload, 'customer_pay') ) {
                    $customer_pay = ArrayUtils::get($payload, 'customer_pay');
                    if(!Validate::isPrice($customer_pay)) {
                        return $this->response([
                            "error" => true,
                            "message" => "Enter a vaild amount"
                        ]);  
                    }
                    $order->total = $customer_pay;
                    $order->update();

	                return $this->modal("SUCCESS", "Successful", "Customer Fee has been updated. Reload page to see changes.");
                }

                if ( ArrayUtils::has($payload, 'writer_pay') ) {
                    $writer_pay = ArrayUtils::get($payload, 'writer_pay');
                    if(!Validate::isPrice($writer_pay)) {
                        return $this->response([
                            "error" => true,
                            "message" => "Enter a vaild amount"
                        ]);  
                    }
                    $order->writer_pay = $writer_pay;
                    $order->update();

	                return $this->modal("SUCCESS", "Successful", "Writer Fee has been updated. Reload page to see changes.");
                }

                if ( ArrayUtils::has($payload, 'editor_pay') ) {
                    $editor_pay = ArrayUtils::get($payload, 'editor_pay');
                    if(!Validate::isPrice($editor_pay)) {
                        return $this->response([
                            "error" => true,
                            "message" => "Enter a vaild amount"
                        ]);  
                    }
                    $order->editor_pay = $editor_pay;
                    $order->update();

	                return $this->modal("SUCCESS", "Successful", "Editor Fee has been updated. Reload page to see changes.");
                }

                return $this->modal("ERROR", "Not found", "Error 404. Resource not found");
                break;

            case 'edit-status':
                $status_id = ArrayUtils::get($payload, 'status_id');
                if( $status_id < 0 ) {
                    return $this->response([
                        "error" => true,
                        "message" => "Select a valid status"
                    ]);  
                }

                $order->status_id = $status_id;
                
                switch($status_id) {
                    case Order::ORDER_PUBLISHED:
                        if(!$order->is_paid) {
                            $order->is_piad = 1;
                            $order->paid_at = DateUtils::now();
                        }

                        if($order->writer_id) {
                            $order->writer_id = 0;
                            $order->writer_assigned = 0;
                            $order->is_writer_confirmed = 0;
                        }

                        break;

                    case Order::WRITER_ASSIGNED:
                        if(Configuration::get('CONFIRM_ORDER_ASSIGN')) {
                            $order->is_writer_confirmed = 0;
                        } else {
                            $order->is_writer_confirmed = 1;
                        }

                        $order->writer_assigned_at = DateUtils::now();
                        break;

                    case Order::DONE:
                        $order->completed_at = DateUtils::now();
                        break;

                    case Order::DELIVERED:
                        if(!$order->completed_at) {
                            $order->completed_at = DateUtils::now();
                        }
                        if(!$order->finished_at) {
                            $order->finished_at = DateUtils::now();
                        }

                        $order->delivered_at = DateUtils::now();
                        break;

                    case Order::FINISHED:
                        if(!$order->completed_at) {
                            $order->completed_at = DateUtils::now();
                        }
                        if(!$order->delivered_at) {
                            $order->delivered_at = DateUtils::now();
                        }
                        if(!$order->finished_at) {
                            $order->finished_at = DateUtils::now();
                        }
                        $order->approved_at = DateUtils::now();

                        break;

                    case Order::CANCELLED:
                        $order->cancelled_at = DateUtils::now();
                        break;
                }

                $order->update();

                $customer = $order->getCustomer();
                $site = new Site( (int) $order->site_id );

                if(Validate::isLoadedObject($customer)) {
                    try {
                        $mailParams = array(
                            'order_domain' => $site->domain,
                            'order_id' => $order->id,
                            'customer_name' => $customer->name,
                        );
    
                        Mail::send(
                            'order_status',
                            "Order #" . $order->id . ": Order status has changed",
                            $mailParams,
                            $customer->email,
                            null,
                            null,
                            null,
                            null,
                            null,
                            null,
                            null,
                            null,
                            null,
                            null,
                            $customer->site_id
                        );  
                    } catch( \Exception $e ) {
                        
                    }
                }

                Hook::exec('actionOrderStatusUpdate', array(
                    'order_id' => $order->id,
                    'newOrderStatus' => $order->status_id
                ));

                return $this->response([
                    'callback' => 'window.location.reload();'
                ]);
                break;

            case 'deadline':
                $handle = ArrayUtils::get($payload, 'handle');
                $deadline = ArrayUtils::get($payload, 'deadline');
                
                if(!$deadline) {
                    return $this->response([
                        "error" => true,
                        "message" => "Enter a valid deadline"
                    ]);
                }

                $deadline = DateUtils::date(strtotime($deadline));

                if ($handle == "customer") {
                    $order->customer_deadline = $deadline;
                    $order->update();
                } elseif ( $handle == "writer" ) {
                    $order->writer_deadline = $deadline;
                    $order->update();
                }

                return $this->modal("SUCCESS", "Successful", "Deadline has been extended. Reload page to see changes.");

                break;

            case 'additional-payment':
                $amount = (float) ArrayUtils::get($payload, 'amount');
                $pages = (int) ArrayUtils::get($payload, 'pages');
                $charts = (int) ArrayUtils::get($payload, 'charts');
                $slides = (int) ArrayUtils::get($payload, 'slides');
                $comments = ArrayUtils::get($payload, 'comments');

                if($amount <= 0) {
                    return $this->response([
                        "error" => true,
                        "message" => "Enter the amount"
                    ]);
                }

                /** Additional Service **/
                $additionalService = new AdditionalService();
                $additionalService->order_id = $order->id;
                $additionalService->total = $amount;

                $additionalService->comment = $comments;

                if($pages) {
                    $additionalService->pages = $pages;
                }

                if($charts) {
                    $additionalService->charts = $charts;
                }

                if($slides) {
                    $additionalService->slides = $slides;
                }

                if (!$additionalService->add()) {
                    return $this->response([
                        "error" => true,
                    ]);
                }

                $payment_url = Configuration::get('SITE_DOMAIN', $order->site_id) . '/dashboard/add-payment/' . $additionalService->id;
                
                return $this->modal("MESSAGE", "Additional Payment Link", $payment_url); 
                break;

            case 'sendToRevision':
                try {
                    $revisionNote = ArrayUtils::get($payload, 'revision_note');
                    if(!$revisionNote) {
                        return $this->response([
                            "error" => true,
                            "message" => "Enter the revision note"
                        ]);
                    }

                    $order->status_id = Order::REVISION;
                    $order->update();

                    $smarty->assign([
                        'order_id' => $order->id,
                        'order_url' => Configuration::get('SITE_DOMAIN') . '/order/' . $order->id,
                        'subject' => "Order #" . $order->id . ": Please revise the order",
                        'body' => $revisionNote
                    ]);
            
                    $revision_body = $smarty->fetch('messages/order_revision.tpl');

                    /** Add Revision Note **/
                    $message = new Message();
                    $message->order_id = $order->id;
                    $message->sender_id = Employee::START_ID;
                    $message->from_department = DEPARTMENT_SUPPORT;
                    $message->to_department = DEPARTMENT_WRITER;
                    $message->subject = "Order #".$order->id.": Please revise the order";
                    $message->body = $revision_body;
                    $message->is_verified = true;
                    $message->verified_at = DateUtils::now();
                    $message->add();
                    
                    $writer = new Employee( (int) $order->writer_id );
                    if(Validate::isLoadedObject($writer)) {
                        Mail::Send(
                            'order_revision',
                            $message->subject,
                            array(
                                'order_id' => $order->id,
                                'order_url' => Configuration::get('SITE_DOMAIN') . '/order/' . $order->id,
                                'body' => $revision_body
                            ),
                            $writer->email
                        ); 
                    }
                } catch( \Exception $e ) {
                }   
                break;
            
            default:
                return $this->modal("ERROR", "Not found", "Error 404. Resource not found");
                break;
        }

        return $this->response([
            'callback' => 'window.location.reload();'
        ]);
    }

    public function sendMessage() {
        $app = $this->app;
        $payload = $app->request->post();
        $user = $app->container->user;

        $order_id = (int) ArrayUtils::get($payload, 'order_id');
        $recepient = (int) ArrayUtils::get($payload, 'recepient');
        $subject = ArrayUtils::get($payload, 'subject');
        $body = ArrayUtils::get($payload, 'message');

        $order = new Order( (int) $order_id );
        if(!Validate::isLoadedObject($order)) {
            return $this->response([
                "error" => true,
                "message" => "This order does not exist"
            ]);
        }

        $message = new Message();

        $send_email_to = array();

        if ( $user->is_admin || $user->is_sub_admin ) {
            $from_department = DEPARTMENT_SUPPORT;
            /** Verify Message */
            $message->is_verified = 1;
            $message->verified_at = DateUtils::now();
        } else {
            $from_department = DEPARTMENT_WRITER;
            $send_email_to[] = Configuration::get('SITE_EMAIL');
            $notification_emails = $app->getNotificationEmails();
            array_merge($send_email_to, $notification_emails);
        }

        if ( $recepient == DEPARTMENT_WRITER ) {
            $writer = new Employee( (int) $order->writer_id );
            if(Validate::isLoadedObject($writer)) {
                $send_email_to[] = $writer->email;
            }
        } elseif ( $recepient == DEPARTMENT_CUSTOMER ) {
            $customer = new Customer( (int) $order->customer_id );
            if(Validate::isLoadedObject($customer)) {
                $send_email_to[] = $customer->email;
            }
        }

        if (!$body) {
            return $this->response([
                "error" => true,
                "message" => "Please enter your message"
            ]);
        }
        
        $message->order_id = $order->id;
        $message->sender_id = $user->id;
        $message->from_department = $from_department;
        $message->to_department = $recepient;
        $message->subject = $subject;
        $message->body = $body;
        $success = $message->add();

        if(!$success) {
			return $this->response([
				"error" => true
			]);
		}

        try {
            $mailParams = array(
                'orderId' => $order->id,
                'message' => Tools::nl2br($message->body)
            );

            $subject = "Order #" . $order->id . ": New message from " . $user->is_admin ? "Support" : "Writer";

			if( $message->to_department == DEPARTMENT_CUSTOMER ) {
                Mail::Send(
                    'order_message',
                    $subject,
                    $mailParams,
                    $send_email_to,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    $customer->site_id
                );	
            } else {
                Mail::Send(
                    'order_message',
                    $subject,
                    $mailParams,
                    $send_email_to
                );	
            }
		} catch( \Exception $e ) {

        }

        return $this->response([
            'callback' => 'window.location.href="/order/'.$order->id.'/messages";'
        ]);	
    }

    public function replyMessage( $message_id ) {
        $app = $this->app;
		$payload = $app->request->post();
        $user = $app->container->user;

        $message = new Message( (int) $message_id );
        if(!Validate::isLoadedObject($message)) {
            return $this->response([
                'error' => true,
                'message' => "This message does not exist"
            ]);
        }

        $order = new Order( (int) $message->order_id );
        if(!Validate::isLoadedObject($message)) {
            return $this->response([
                'error' => true,
                'message' => "This message does not have an existing order"
            ]);
        }

        $body = ArrayUtils::get($payload, 'reply');
        if (!$body) {
            return $this->response([
                "error" => true,
                "message" => "Please enter your message"
            ]);
        }

        $reply = new Message();

        $send_email_to = array();

        if ( $user->is_admin || $user->is_sub_admin ) {
            $from_department = DEPARTMENT_SUPPORT;
            $reply->is_verified = 1;
            $reply->verified_at = DateUtils::now();
		} else {
            $from_department = DEPARTMENT_WRITER;
            $send_email_to[] = Configuration::get('SITE_EMAIL');
            $notification_emails = $app->getNotificationEmails();
            array_merge($send_email_to, $notification_emails);
        }

		$reply->order_id = $order->id;
        $reply->parent_id = $message->id;
        $reply->sender_id = $user->id;
		$reply->from_department = $from_department;
		$reply->to_department = $message->from_department;
		$reply->subject = $message->subject;
        $reply->body = $body;
        $success = $reply->add();
        
        if ( $reply->to_department == DEPARTMENT_WRITER ) {
            $writer = $order->getWriter();
            if(Validate::isLoadedObject($writer)) {
                $send_email_to[] = $writer->email;
            }
        } elseif ( $reply->to_department == DEPARTMENT_CUSTOMER ) {
            $customer = $order->getCustomer();
            if(Validate::isLoadedObject($customer)) {
                $send_email_to[] = $customer->email;
            }
        }

        if(!$success) {
			return $this->response([
				"error" => true
			]);
		}

        try {
            $mailParams = array(
                'orderId' => $order->id,
                'message' => $reply->body
            );

            $subject = "Order #" . $order->id . ": New message from " . $user->is_admin ? "Support" : "Writer";

            if( $reply->to_department == DEPARTMENT_CUSTOMER ) {
                Mail::Send(
                    'order_message',
                    $subject,
                    $mailParams,
                    $send_email_to,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    $customer->site_id
                );	
            } else {
                Mail::Send(
                    'order_message',
                    $subject,
                    $mailParams,
                    $send_email_to
                );	
            }
			
		} catch( \Exception $e ) {

        }

        return $this->response([
            'callback' => 'window.location.href="/order/'.$order->id.'/messages";'
        ]);	
    }

    public function readMessage( $message_id ) {
        $app = $this->app;
        $user = $app->container->user;

        $message = new Message( (int) $message_id );
        if(Validate::isLoadedObject($message)) {
            if( $message->sender_id != $user->id ) {
                $message->is_viewed = 1;
                $message->viewed_at = DateUtils::now();
                $message->update();
            }
        }

        return $this->response([
            'success' => true
        ]);
    }

    public function uploadFiles( $order_id ) {
        $app = $this->app;
        $payload = $app->request->post();
		$params = $app->request->get();
        $user = $app->container->user;
        
        $order = new Order( (int) $order_id );
		if (!Validate::isLoadedObject($order)) {
            return $this->response([
                'error' => true,
                'message' => "This order does not exist"
            ]);
        }
        
        $files = ArrayUtils::get($payload, 'files');
		if (!is_array($files) || empty($files)) {
            return $this->response([
                'error' => true,
                'message' => "Select the files to upload"
            ]);
        }

        $upload_for = ArrayUtils::get($params, "upload_for");
        if ( $upload_for == "customer" ) {
            $uploader_id = $order->customer_id;
        } elseif ( $upload_for == "writer" ) {
            $uploader_id = $order->writer_id;
        } elseif ( $upload_for == "editor" && $order->editor_id ) {
            $uploader_id = $order->editor_id;
        } elseif ( $upload_for == "support" ) {
            $uploader_id = Employee::START_ID;
        } else {
            $uploader_id = $user->id;
        }
        
		foreach ($files as $uploaded_file) {
            $file_id = (int) ArrayUtils::get($uploaded_file, 'id');
            $file_type_id = (int) ArrayUtils::get($uploaded_file, 'uploadTypeId');
            $file_type = new UploadType( $file_type_id );
            if(!Validate::isLoadedObject($file_type)) {
                return $this->response([
                    'error' => true,
                    'message' => "Select the file type"
                ]);
            }
            
            $file = new File( (int) $file_id );
            if ( Validate::isLoadedObject( $file) ) {
                $file->order_id = $order->id;
                $file->uploader_id = $uploader_id;
                $file->file_type_id = $file_type->id;
                $file->file_description = ArrayUtils::get($file_type, 'description');
                $file->update();
            }	
		}

        return $this->response([
            'callback' => 'window.location.href="/order/'.$order->id.'/files";'
        ]);	
    }   

    public function feedbackReply( $feedbackId ) {
        $app = $this->app;
        $payload = $app->request->post();
        $user = $app->container->user;

        $rating = new Rating( (int) $feedbackId );
        if(!Validate::isLoadedObject($rating)) {
            return $this->modal("ERROR", "This feedback does not exist");
        }

        $order = new Order( (int) $rating->order_id );
        if(!Validate::isLoadedObject($order)) {
            return $this->modal("ERROR", "Reply not Sent", "A reply could not be sent to the customer.");
        }

        $customer = new Customer( (int) $order->customer_id );
        if(!Validate::isLoadedObject($customer)) {
            return $this->modal("ERROR", "Reply not Sent", "A reply could not be sent to the customer.");
        }

        $reply = ArrayUtils::get($payload, 'reply');
        if(!$reply) {
            return $this->response([
                "error" => true,
                "message" => "Please enter the reply"
            ]);
        }

        try {
            $mailParams = array(
                'order_id' => $order->id,
                'name' => $customer->name ? $customer->name : 'Customer #' . $customer->id,
                'reply' => $reply
            );

            Mail::send(
                'feedback_reply',
                'Thank you for your feedback',
                $mailParams,
                $customer->email,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                $customer->site_id
            );  
        } catch( \Exception $e ) {
        }

        return $this->modal("SUCCESS", "Reply Sent", "Reply was successfuly sent to the customer");
    }
}