<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\DeliveryAddress;
use App\Order;
use App\OrderDetail;
use App\Payment;
use App\ProductDetail;
use App\Events\NotifyEvent;
use App\Notify;
use Stripe\Charge;
use Stripe\Customer;
use Stripe\Stripe;
use Validator;
use Cart;
use Mail;


class CartController extends Controller
{
    const ITEM_PER_PAGE = 25;

    public function index()
    {
        $cartCollection = Cart::getContent();
        $cartTotalAmount = Cart::getTotal();
        $totalShipping = 0;

        $list = [];
        foreach ($cartCollection as $item) {
            $list[] = $item;
            $totalShipping += 16500;
        }

        return response()->json([
            'status'         => 'success',
            'data'           => $list,
            'total'          => $cartCollection->count(),
            'total_amount'   => $cartTotalAmount,
            'total_shipping' => $totalShipping,
        ], 200);
    }

    public function statistic()
    {
        //$cartTotal = Cart::getTotalQuantity();
        //Cart::clear();

        $cartCollection = Cart::getContent();
        $cartTotal = $cartCollection->count();

        return response()->json(['status' => 'success', 'data' => ['total' => $cartTotal]], 200);
    }

    public function show($id = 0)
    {
        $item = Cart::get($id);

        return response()->json(['status' => 'success', 'data' => $item], 200);
    }

    public function store(Request $request)
    {
        $validator = Validator::make($request->all(), ['id' => ['required'], 'code' => ['required'], 'price' => ['required'], 'purchase_id' => ['required']]);
        if ($validator->fails()) return response()->json(['errors' => $validator->errors()], 403);
        $params = $request->all();

        $productDetail = ProductDetail::with('option_detail', 'product')
            ->where('code', $params['code'])
            ->where('product_id', $params['id'])
            ->first();

        if (!$productDetail) return response()->json(['status' => 'error', 'errors' => 'Product not found'], 200);

        $code = $productDetail->code;
        $productShippingCost = $productDetail->product->shipping_cost;
        $cItem = Cart::get($code);
        if (!isset($cItem) || $cItem == null) {
            $productId = $productDetail->product->id;
            $productName = $productDetail->product->name;
            $productImage = $productDetail->product->image;
            $productDiscount = ($productDetail->product->discount != null && $productDetail->product->discount != "") ? $productDetail->product->discount : 0;
            $productItemCatalogPrice = $productDetail->price;
            $discountAmount = 0;
            if($productDiscount > 0) $discountAmount = ceil($productItemCatalogPrice * ($productDiscount / 100));
            $productItemPrice = ceil($productItemCatalogPrice - $discountAmount);
            $productTaxCost = ceil(($productItemPrice * (10 / 100)));
            $productTotalPrice = ceil($productItemPrice + $productShippingCost + $productTaxCost);
            $productPossibleDeliveryTime = ($productDetail->product->possible_delivery_time != null && $productDetail->product->possible_delivery_time != "") ? $productDetail->product->possible_delivery_time : 20;

            $productManufacturerName = '';
            $productManufacturerImage = '';
            if (isset($productDetail->product->manufacturer) && $productDetail->product->manufacturer != null) {
                $productManufacturerName = $productDetail->product->manufacturer->name;
                $productManufacturerImage = $productDetail->product->manufacturer->image;
            }

            $options = [];
            foreach ($productDetail->option_detail as $item) {
                if (isset($item->detail)) {
                    $oName = '';
                    if (isset($item->detail->option)) $oName = $item->detail->option->name;
                    $options[] = [
                        'id'    => $item->detail->id,
                        'name'  => $item->detail->name,
                        'image' => $item->detail->image,
                        'label' => $oName,
                    ];
                }
            }

            Cart::add([
                'id'         => $code,
                'name'       => $productName,
                'price'      => $productTotalPrice,
                'quantity'   => 1,
                'attributes' => [
                    'id'                     => $productId,
                    'name'                   => $productName,
                    'image'                  => $productImage,
                    'catalog_price'          => $productItemCatalogPrice,
                    'discount'               => $productDiscount,
                    'price'                  => $productItemPrice,
                    'tax'                    => $productTaxCost,
                    'shipping_cost'          => $productShippingCost,
                    'manufacturer_name'      => $productManufacturerName,
                    'manufacturer_image'     => $productManufacturerImage,
                    'options'                => $options,
                    'purchase_id'            => $params['purchase_id'],
                    'possible_delivery_time' => $productPossibleDeliveryTime
                ]
            ]);
        } else {
            Cart::update($code, ['quantity' => 1]);
        }

        return response()->json(['status' => 'success', 'message' => ''], 200);
    }

    public function order(Request $request)
    {
        $params = $request->all();
        $cartTotalAmount = Cart::getTotal();
        if ($cartTotalAmount <= 0) return response()->json(['status' => 'error', 'code' => null], 200);

        do {
            $orderCode = rand(11111, 99999) . rand(11111, 99999) . rand(11111, 99999);
            $checkOrder = Order::where(['code' => $orderCode])->first();
        } while (isset($checkOrder));

        $paymentEmail = $params['payment']['email'];
        $paymentName = $params['first_name'] . " " . $params['last_name'];
        $line = "〒" . $params['post_code'] . " " . $params['address'] . " " . $params['address2'] . " " . $params['address3'];
        $postCode = $params['post_code'];
        $city = $params['address'];

        if ($params['is_other_address'] == true || $params['is_other_address'] == "true") {
            $paymentName = $params['other']['first_name'] . " " . $params['other']['last_name'];
            $line = "〒" . $params['other']['post_code'] . " " . $params['other']['address'] . " " . $params['other']['address2'] . " " . $params['other']['address3'];
            $postCode = $params['other']['post_code'];
            $city = $params['other']['address'];
        }

        $paymentResult = null;
        $paymentCustomer = null;
        if ($params['payment_method'] == 0 || $params['payment_method'] == "0") {
            $stripeToken = $params['payment']['token']['id'];
            Stripe::setApiKey(config('stripe.stripe_secret'));
            $paymentCustomer = Customer::create(array(
                "address" => [
                    "line1"       => $line,
                    "postal_code" => $postCode,
                    "city"        => $city,
                    "state"       => "JP",
                    "country"     => "JP",
                ],
                "email"   => $paymentEmail,
                "name"    => $paymentName,
                "source"  => $stripeToken
            ));

            $paymentResult = Charge::create([
                "amount"      => $cartTotalAmount,
                "currency"    => "jpy",
                "customer"    => $paymentCustomer->id,
                "description" => "JISHODOでオーダーインボイス番号#" . $orderCode . "の支払い。",
                "shipping"    => [
                    "name"    => $paymentName,
                    "address" => [
                        "line1"       => $line,
                        "postal_code" => $postCode,
                        "city"        => $city,
                        "state"       => "JP",
                        "country"     => "JP",
                    ],
                ]
            ]);

            logger("customer: " . $paymentCustomer);
            logger("rs payment: " . $paymentResult);
            logger("payment: " . json_encode($params['payment']));
        }

        $paymentStatus = ($params['payment_method'] == 1) ? 0 : 1;
        $userId = auth('api')->user()->id;

        //Order
        $order = Order::create([
            'code'           => $orderCode,
            'type'           => ($userId != null && $userId != "") ? "user" : "guest",
            'user_id'        => $userId,
            'total_price'    => $cartTotalAmount,
            'note'           => $params['notes'],
            'payment_method' => ($params['payment_method'] == 0) ? 0 : 1,
            'payment_status' => $paymentStatus,
            'status'         => 0, //0: New order and wait confirm, 1: Confirmed, 2: Processing, 3: Shipping, 4: Delivered
            'created_at'     => date('Y-m-d H:i:s'),
            'updated_at'     => date('Y-m-d H:i:s'),
        ]);

        //Order Detail
        $cartCollection = Cart::getContent();
        foreach ($cartCollection as $item) {
            $productDetail = ProductDetail::where('code', $item['id'])->first();
            OrderDetail::create([
                'order_id'          => $order->id,
                'product_id'        => $item['attributes']['id'],
                'product_detail_id' => $productDetail->id,
                'product_name'      => $item['name'],
                'product_image'     => $item['attributes']['image'],
                'order_method'      => $item['attributes']['purchase_id'],
                'discount'          => $item['attributes']['discount'],
                'catalog_price'     => $item['attributes']['catalog_price'],
                'price'             => $item['attributes']['price'],
                'shipping_cost'     => $item['attributes']['shipping_cost'],
                'quantity'          => $item['quantity'],
                'total_price'       => $item['price'],
                'created_at'        => date('Y-m-d H:i:s'),
                'updated_at'        => date('Y-m-d H:i:s'),
            ]);
        }

        //DeliveryAddress
        $deliFirstName = $params['first_name'];
        $deliLastName = $params['last_name'];
        $deliFuriganaFirstName = $params['furigana_first_name'];
        $deliFuriganaLastName = $params['furigana_last_name'];
        $deliPostCode = $params['post_code'];
        $deliAddress = $params['address'];
        $deliAddress2 = $params['address2'];
        $deliAddress3 = $params['address3'];
        $deliPhoneNumber = $params['phone_number'];
        $deliEmail = $params['email'];

        if ($params['is_other_address']) {
            $deliFirstName = $params['other']['first_name'];
            $deliLastName = $params['other']['last_name'];
            $deliFuriganaFirstName = $params['other']['furigana_first_name'];
            $deliFuriganaLastName = $params['other']['furigana_last_name'];
            $deliPostCode = $params['other']['post_code'];
            $deliAddress = $params['other']['address'];
            $deliAddress2 = $params['other']['address2'];
            $deliAddress3 = $params['other']['address3'];
            $deliPhoneNumber = $params['other']['phone_number'];
        }

        if (($deliEmail == null || $deliEmail == "") && $userId != null) {
            $deliEmail = auth('api')->user()->email;
        }

        DeliveryAddress::create([
            'order_id'            => $order->id,
            'first_name'          => $deliFirstName,
            'last_name'           => $deliLastName,
            'furigana_first_name' => $deliFuriganaFirstName,
            'furigana_last_name'  => $deliFuriganaLastName,
            'post_code'           => $deliPostCode,
            'city'                => $deliAddress,
            'district'            => $deliAddress2,
            'address'             => $deliAddress3,
            'phone_number'        => $deliPhoneNumber,
            'email'               => $deliEmail,
            'user_id'             => $userId,
            'is_default'          => 0,
            'created_at'          => date('Y-m-d H:i:s'),
            'updated_at'          => date('Y-m-d H:i:s'),
        ]);

        //Payment
        $payment = null;
        if ($params['payment_method'] == 0 && $paymentResult != null) {
            $paymentResultJs = json_encode($paymentResult);
            $paymentResultArr = json_decode($paymentResultJs, true);

            $payment = Payment::create([
                'order_id'               => $order->id,
                'code'                   => $paymentResultArr['id'],
                'total'                  => $paymentResultArr['amount'],
                'amount_captured'        => $paymentResultArr['amount_captured'],
                'amount_refunded'        => $paymentResultArr['amount_refunded'],
                'application_fee'        => $paymentResultArr['application_fee'],
                'application_fee_amount' => $paymentResultArr['application_fee_amount'],
                'currency'               => $paymentResultArr['currency'],
                'type'                   => $paymentResultArr['payment_method_details']['type'],
                'provider'               => $paymentResultArr['balance_transaction'],
                'customer'               => $paymentResultArr['customer'],
                'payment_method'         => $paymentResultArr['payment_method'],
                'brand'                  => isset($paymentResultArr['payment_method_details']['card']) ? $paymentResultArr['payment_method_details']['card']['brand'] : '',
                'funding'                => isset($paymentResultArr['payment_method_details']['card']) ? $paymentResultArr['payment_method_details']['card']['funding'] : '',
                'network'                => isset($paymentResultArr['payment_method_details']['card']) ? $paymentResultArr['payment_method_details']['card']['network'] : '',
                'country'                => isset($paymentResultArr['payment_method_details']['card']) ? $paymentResultArr['payment_method_details']['card']['country'] : '',
                'last4'                  => isset($paymentResultArr['payment_method_details']['card']) ? $paymentResultArr['payment_method_details']['card']['last4'] : '',
                'exp_month'              => isset($paymentResultArr['payment_method_details']['card']) ? $paymentResultArr['payment_method_details']['card']['exp_month'] : '',
                'exp_year'               => isset($paymentResultArr['payment_method_details']['card']) ? $paymentResultArr['payment_method_details']['card']['exp_year'] : '',
                'failure_code'           => $paymentResultArr['failure_code'],
                'failure_message'        => $paymentResultArr['failure_message'],
                'content'                => json_encode($paymentResult),
                'customer_info'          => json_encode($paymentCustomer),
                /*'error_content'          => $paymentResultArr['amount_refunded'],*/
                'finished_at'            => date('Y-m-d H:i:s', $paymentResultArr['created']),
                'status'                 => ($paymentResultArr['paid'] && $paymentResultArr['status'] == "succeeded") ? 1 : 0,
                'created_at'             => date('Y-m-d H:i:s'),
                'updated_at'             => date('Y-m-d H:i:s'),
            ]);
        }

        //Clear Cart
        Cart::clear();

        //Send Email
        $data = $params;
        $data['site'] = url("/");
        $data['code'] = $orderCode;
        $data['total_amount'] = "￥" . number_format($cartTotalAmount);
        $data['payment_method'] = ($params['payment_method'] == 0) ? "クレジットカード" : "前払い";
        $data['payment_status'] = ($params['payment_method'] == 0 && $payment != null && $payment->status == 1) ? "有料" : "未払い";
        $data['note'] = $params['notes'];
        $data['name'] = $deliFirstName . " " . $deliLastName;
        $data['furigana'] = $deliFuriganaFirstName . " " . $deliFuriganaLastName;
        $data['address'] = "〒" . $deliPostCode . " " . $deliAddress . " " . $deliAddress2 . " " . $deliAddress3;
        $data['phone_number'] = $deliPhoneNumber;
        $data['email'] = $deliEmail;
        $userEmail = $deliEmail;
        $notifyContent = ['code' => $orderCode];

        try {
            Notify::create([
                'content'      => "[Order] a new order #" . $orderCode,
                'module'       => 'order',
                'item_id'      => $orderCode,
                'item_content' => json_encode($notifyContent),
                'created_at'   => date('Y-m-d H:i:s'),
                'updated_at'   => date('Y-m-d H:i:s'),
            ]);
            event(new NotifyEvent());

            //admin
            //hunters2fujiyoshi@gmail.com
            Mail::send('emails.new_order_admin', $data, function ($message) use ($orderCode) {
                $message->from(config('mail.from.address'), config('mail.from.name'));
                $message->to(config('settings.admin_email'));
                $message->subject("【" . config('mail.from.name') . "】新しい注文があります #" . $orderCode);
            });
            logger("[Email] Sent admin order email to: " . config('settings.admin_email'));

            //user
            Mail::send('emails.new_order_user', $data, function ($message) use ($userEmail, $orderCode) {
                $message->from(config('mail.from.address'), config('mail.from.name'));
                $message->to($userEmail);
                $message->subject("【" . config('mail.from.name') . "】注文いただきありがとうございます #" . $orderCode);
            });
            logger("[Email] Sent user order email to: " . $userEmail);
        } catch (\Exception $exception) {
            logger($exception->getMessage());
        } finally {
            return response()->json(['status' => 'success', 'code' => $orderCode], 200);
        }
    }

    public function update(Request $request, $id = 0)
    {
        $validator = Validator::make($request->all(), ['id' => ['required'], 'code' => ['required'], 'quantity' => ['required']]);
        if ($validator->fails()) return response()->json(['errors' => $validator->errors()], 403);
        $params = $request->all();

        $productDetail = ProductDetail::with('option_detail', 'product')
            ->where('code', $params['code'])
            ->where('product_id', $params['id'])
            ->first();

        if (!$productDetail) return response()->json(['status' => 'error', 'errors' => 'Product not found'], 200);

        $code = $productDetail->code;
        $quantity = ($params['quantity'] > 0) ? $params['quantity'] : 1;

        $cItem = Cart::get($code);
        if ($cItem) {
            Cart::update($code, [
                'quantity' => [
                    'relative' => false,
                    'value'    => $quantity
                ],
            ]);
        }

        return response()->json(['status' => 'success', 'message' => ''], 200);
    }

    public function destroy($id = 0)
    {
        Cart::remove($id);

        return response()->json(null, 204);
    }

}
