#!/usr/bin/python
# -*- coding: utf-8 -*-

# Hive Budy
# Copyright (c) 2008-2020 Hive Solutions Lda.
#
# This file is part of Hive Budy.
#
# Hive Budy is free software: you can redistribute it and/or modify
# it under the terms of the Apache License as published by the Apache
# Foundation, either version 2.0 of the License, or (at your option) any
# later version.
#
# Hive Budy is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# Apache License for more details.
#
# You should have received a copy of the Apache License along with
# Hive Budy. If not, see <http://www.apache.org/licenses/>.

__author__ = "João Magalhães <joamag@hive.pt>"
""" The author(s) of the module """

__version__ = "1.0.0"
""" The version of the module """

__revision__ = "$LastChangedRevision$"
""" The revision number of the module """

__date__ = "$LastChangedDate$"
""" The last change date of the module """

__copyright__ = "Copyright (c) 2008-2020 Hive Solutions Lda."
""" The copyright for the module """

__license__ = "Apache License, Version 2.0"
""" The license for the module """

import appier

import budy

from . import root

class OrderAPIController(root.RootAPIController):

    @appier.route("/api/orders", "GET", json = True)
    @appier.ensure(token = "admin")
    def list(self):
        object = appier.get_object(alias = True, find = True, sort = [("id", -1)])
        orders = budy.Order.find(eager_l = True, map = True, **object)
        return orders

    @appier.route("/api/orders/complex.csv", "GET")
    @appier.ensure(token = "admin")
    def complex_csv(self):
        start = self.field("start", cast = int)
        end = self.field("end", cast = int)
        paid = self.field("paid", True, cast = bool)
        object = appier.get_object(
            alias = True,
            find = True,
            limit = 0,
            sort = [("id", -1)]
        )
        id = object.get("id", {})
        if start: id["$gte"] = start
        if end: id["$lte"] = end
        if start or end: object["id"] = id
        if paid: object["paid"] = True
        orders = budy.Order.find(**object)
        orders_s = [(
            "id",
            "reference",
            "date",
            "status",
            "email",
            "account",
            "store",
            "product",
            "gender",
            "size",
            "quantity",
            "total",
            "taxes",
            "currency",
            "first_name",
            "last_name",
            "billing_address",
            "billing_city",
            "billing_state",
            "billing_postal_code",
            "billing_country",
            "billing_phone",
            "shipping_address",
            "shipping_city",
            "shipping_state",
            "shipping_postal_code",
            "shipping_country",
            "shipping_phone",
            "shipping_cost"
        )]
        for order in orders:
            for line in order.lines:
                if not line.product: continue
                account = order.account
                shipping_address = order.shipping_address
                billing_address = order.billing_address
                shipping_cost = order.shipping_cost
                order_s = (
                    order.id,
                    order.reference,
                    order.created_d.strftime("%d/%m/%Y"),
                    order.status,
                    order.email,
                    account.username,
                    order.store and order.store.name,
                    line.product.short_description,
                    line.product.gender,
                    line.size,
                    line.quantity,
                    line.total,
                    line.taxes,
                    line.currency,
                    billing_address.first_name,
                    billing_address.last_name,
                    billing_address.address,
                    billing_address.city,
                    billing_address.state,
                    billing_address.postal_code,
                    billing_address.country,
                    billing_address.phone_number,
                    shipping_address and shipping_address.address,
                    shipping_address and shipping_address.city,
                    shipping_address and shipping_address.state,
                    shipping_address and shipping_address.postal_code,
                    shipping_address and shipping_address.country,
                    shipping_address and shipping_address.phone_number,
                    shipping_cost
                )
                orders_s.append(order_s)
        result = appier.serialize_csv(orders_s, delimiter = ",")
        self.content_type("text/csv")
        return result

    @appier.route("/api/orders/ctt.csv", "GET")
    @appier.ensure(token = "admin")
    def ctt_csv(self):
        start = self.field("start", cast = int)
        end = self.field("end", cast = int)
        paid = self.field("paid", True, cast = bool)
        sms = self.field("sms", False, cast = bool)
        quantity = self.field("quantity", 1, cast = int)
        weight = self.field("weight", 100, cast = int)
        object = appier.get_object(
            alias = True,
            find = True,
            limit = 0,
            sort = [("id", -1)]
        )
        id = object.get("id", {})
        if start: id["$gte"] = start
        if end: id["$lte"] = end
        if start or end: object["id"] = id
        if paid: object["paid"] = True
        orders = self.admin_part._find_view(budy.Order, **object)
        orders_s = []
        for order in orders:
            shipping_address = order.shipping_address
            postal_code = shipping_address.postal_code or ""
            if not "-" in postal_code: postal_code += "-"
            weight_s = "%.2f" % (order.quantity * weight)
            weight_s = weight_s.replace(".", ",")
            line = dict(
                reference = order.reference,
                quantity = int(order.quantity) if quantity == None else quantity,
                weight = weight_s,
                price = "0ue",
                destiny = shipping_address.full_name[:60],
                title = order.account.title[:20],
                name = shipping_address.full_name[:60],
                address = shipping_address.address[:60],
                town = shipping_address.city[:50],
                zip_code_4 = postal_code.split("-", 1)[0][:4],
                zip_code_3 = postal_code.split("-", 1)[1][:3],
                not_applicable_1 = "",
                observations = "",
                back = 0,
                document_code = "",
                phone_number = (shipping_address.phone_number or "").replace("+", "00")[:15],
                saturday = 0,
                email = (order.email or "")[:200],
                country = order.country,
                fragile = 0,
                not_applicable_2 = "",
                document_collection = "",
                code_email = "",
                mobile_phone = (shipping_address.phone_number or "").replace("+", "00")[:15],
                second_delivery = 0,
                delivery_date = "",
                return_signed_document = 0,
                expeditor_instructions = 0,
                sms = 1 if sms else 0,
                not_applicable_3 = "",
                printer = "",
                ticket_machine = "",
                at_code = ""
            )
            order_s = (
                line["reference"],
                str(line["quantity"]),
                line["weight"],
                line["price"],
                line["destiny"],
                line["title"],
                line["name"],
                line["address"],
                line["town"],
                line["zip_code_4"],
                line["zip_code_3"],
                line["not_applicable_1"],
                line["observations"],
                str(line["back"]),
                line["document_code"],
                line["phone_number"],
                str(line["saturday"]),
                line["email"],
                line["country"],
                str(line["fragile"]),
                line["not_applicable_2"],
                line["document_collection"],
                line["code_email"],
                line["mobile_phone"],
                str(line["second_delivery"]),
                line["delivery_date"],
                str(line["return_signed_document"]),
                str(line["expeditor_instructions"]),
                str(line["sms"]),
                line["not_applicable_3"],
                line["printer"],
                line["ticket_machine"],
                line["at_code"]
            )
            orders_s.append(order_s)
        result = appier.serialize_csv(
            orders_s,
            encoding = "Cp1252",
            errors = "ignore",
            delimiter = "+"
        )
        result = appier.legacy.bytes(
            result,
            encoding = "Cp1252",
            errors = "ignore"
        )
        self.content_type("text/csv")
        return result

    @appier.route("/api/orders/<str:key>", "GET", json = True)
    def show(self, key):
        order = budy.Order.get(key = key)
        order.refresh_s(
            currency = order.payment_currency or self.currency,
            country = order.shipping_country or self.country
        )
        order = order.reload(
            eager = (
                "lines.product.images",
                "lines.product.brand"
            ),
            map = True
        )
        return order

    @appier.route("/api/orders/<str:key>/store", "PUT", json = True)
    @appier.ensure(token = "user")
    def set_store(self, key):
        data = appier.request_json()
        store_id = data["store_id"]
        store = budy.Store.get(id = store_id)
        order = budy.Order.get(key = key, rules = False)
        order.store = store
        order.save()
        order = order.reload(map = True)
        return order

    @appier.route("/api/orders/<str:key>/shipping_address", "PUT", json = True)
    @appier.ensure(token = "user")
    def set_shipping_address(self, key):
        data = appier.request_json()
        unset_store = data.get("unset_store", True)
        address = budy.Address.new()
        address.save()
        order = budy.Order.get(key = key, rules = False)
        order.shipping_address = address
        if unset_store: order.store = None
        order.save()
        order = order.reload(map = True)
        return order

    @appier.route("/api/orders/<str:key>/billing_address", "PUT", json = True)
    @appier.ensure(token = "user")
    def set_billing_address(self, key):
        data = appier.request_json()
        unset_store = data.get("unset_store", False)
        address = budy.Address.new()
        address.save()
        order = budy.Order.get(key = key, rules = False)
        order.billing_address = address
        if unset_store: order.store = None
        order.save()
        order = order.reload(map = True)
        return order

    @appier.route("/api/orders/<str:key>/store_shipping", "PUT", json = True)
    @appier.ensure(token = "user")
    def set_store_shipping(self, key):
        order = budy.Order.get(key = key, rules = False)
        order.verify_store()
        store = order.store
        address = store.address.clone()
        address.save()
        order.shipping_address = address
        order.save()
        order = order.reload(map = True)
        return order

    @appier.route("/api/orders/<str:key>/store_billing", "PUT", json = True)
    @appier.ensure(token = "user")
    def set_store_billing(self, key):
        order = budy.Order.get(key = key, rules = False)
        order.verify_store()
        store = order.store
        address = store.address.clone()
        address.save()
        order.billing_address = address
        order.save()
        order = order.reload(map = True)
        return order

    @appier.route("/api/orders/<str:key>/ip_address", "PUT", json = True)
    @appier.ensure(token = "user")
    def set_ip_address(self, key):
        data = appier.request_json()
        ip_address = data["ip_address"]
        order = budy.Order.get(key = key, rules = False)
        order.set_ip_address_s(ip_address)
        order = order.reload(map = True)
        return order

    @appier.route("/api/orders/<str:key>/email", "PUT", json = True)
    @appier.ensure(token = "user")
    def set_email(self, key):
        data = appier.request_json()
        email = data["email"]
        order = budy.Order.get(key = key, rules = False)
        order.email = email
        order.save()
        order = order.reload(map = True)
        return order

    @appier.route("/api/orders/<str:key>/gift_wrap", "PUT", json = True)
    @appier.ensure(token = "user")
    def set_gift_wrap(self, key):
        data = appier.request_json()
        gift_wrap = data["gift_wrap"]
        order = budy.Order.get(key = key, rules = False)
        order.gift_wrap = gift_wrap
        order.save()
        order = order.reload(map = True)
        return order

    @appier.route("/api/orders/<str:key>/referral", "PUT", json = True)
    @appier.ensure(token = "user")
    def set_referral(self, key):
        data = appier.request_json()
        referral_name = data["name"]
        order = budy.Order.get(key = key, rules = False)
        referral = budy.Referral.get(name = referral_name)
        order.set_referral_s(referral)
        order = order.reload(map = True)
        return order

    @appier.route("/api/orders/<str:key>/voucher", "PUT", json = True)
    @appier.ensure(token = "user")
    def set_voucher(self, key):
        strict = self.field("strict", False, cast = bool)
        empty_vouchers = self.field("empty_vouchers", True, cast = bool)
        data = appier.request_json()
        voucher_key = data["key"]
        order = budy.Order.get(key = key, rules = False)
        if empty_vouchers: order.empty_vouchers_s()
        voucher = budy.Voucher.get(
            key = voucher_key,
            raise_e = strict
        )
        if not voucher: return
        order.set_voucher_s(voucher)
        order = order.reload(map = True)
        return order

    @appier.route("/api/orders/<str:key>/meta", "PUT", json = True)
    @appier.ensure(token = "user")
    def set_meta(self, key):
        name = self.field("name", mandatory = True, not_empty = True)
        value = self.field("value", mandatory = True)
        order = budy.Order.get(key = key, rules = False)
        order.set_meta_s(name, value)
        order = order.reload(map = True)
        return order

    @appier.route("/api/orders/<str:key>/account", "PUT", json = True)
    @appier.ensure(token = "user")
    def set_account(self, key):
        order = budy.Order.get(key = key, rules = False)
        account = budy.BudyAccount.from_session()
        order.set_account_s(account)
        order = order.reload(map = True)
        return order

    @appier.route("/api/orders/<str:key>/wait_payment", "PUT", json = True)
    @appier.ensure(token = "user")
    def wait_payment(self, key):
        empty_bag = self.field("empty_bag", True, cast = bool)
        order = budy.Order.get(key = key, rules = False)
        result = order.wait_payment_s(notify = True)
        bag = budy.Bag.from_session()
        if empty_bag and bag: bag.empty_s()
        order = order.reload(map = True)
        redirect_url = result if appier.legacy.is_string(result) else None
        return dict(
            redirect_url = redirect_url,
            order = order
        )

    @appier.route("/api/orders/<str:key>/pay", "PUT", json = True)
    @appier.ensure(token = "user")
    def pay(self, key):
        data = appier.request_json()
        empty_bag = self.field("empty_bag", True, cast = bool)
        order = budy.Order.get(key = key, rules = False)
        result = order.pay_s(payment_data = data, notify = True)
        bag = budy.Bag.from_session()
        if empty_bag and bag: bag.empty_s()
        order = order.reload(map = True)
        redirect_url = result if appier.legacy.is_string(result) else None
        return dict(
            redirect_url = redirect_url,
            order = order
        )

    @appier.route("/api/orders/<str:key>/end_pay", "PUT", json = True)
    @appier.ensure(token = "user")
    def end_pay(self, key):
        data = appier.request_json()
        empty_bag = self.field("empty_bag", True, cast = bool)
        order = budy.Order.get(key = key, rules = False)
        result = order.end_pay_s(payment_data = data, strict = True, notify = True)
        bag = budy.Bag.from_session()
        if empty_bag and bag: bag.empty_s()
        order = order.reload(map = True)
        redirect_url = result if appier.legacy.is_string(result) else None
        return dict(
            redirect_url = redirect_url,
            order = order
        )

    @appier.route("/api/orders/<str:key>/cancel", "PUT", json = True)
    @appier.ensure(token = "user")
    def cancel(self, key):
        data = appier.request_json()
        order = budy.Order.get(key = key, rules = False)
        result = order.cancel_s(data, notify = True)
        order = order.reload(map = True)
        redirect_url = result if appier.legacy.is_string(result) else None
        return dict(
            redirect_url = redirect_url,
            order = order
        )

    @appier.route("/api/orders/<str:key>/lines.csv", "GET")
    @appier.ensure(token = "admin")
    def lines_csv(self, key):
        order = budy.Order.get(key = key)
        lines_s = [(
            "id",
            "product",
            "product_id",
            "quantity",
            "size",
            "scale",
            "gender",
            "line_total",
            "currency",
            "order_id",
            "order_reference",
            "order_total",
            "order_status",
            "account",
            "date",
        )]
        for line in order.lines:
            if not line.product: continue
            line_s = (
                line.id,
                line.product.id,
                line.product.product_id,
                line.quantity,
                line.size,
                line.scale,
                line.product.gender,
                line.total,
                line.currency,
                order.id,
                order.reference,
                order.total,
                order.status,
                order.account.username,
                order.created_d.strftime("%d/%m/%Y"),
            )
            lines_s.append(line_s)

        result = appier.serialize_csv(lines_s, delimiter = ",")
        self.content_type("text/csv")
        return result
