from django.shortcuts import render
from django.http import HttpResponse, HttpResponseRedirect, JsonResponse
from django.views.generic import ListView
from django.db import transaction

from .models import (
    Sale, SaleLine, Product, ProductCategory, Payment, PaymentMethods)
from .forms import (
    ImportProductsForm,
    PurchaseForm,
    SaleLineFormSet,
    ReconciliationJarForm,
    PurchaseSummaryForm)

import csv
import io
import json
from decimal import Decimal


class DecimalEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, Decimal):
            return float(obj)
        return json.JSONEncoder.default(self, obj)


def index(request):
    return render(request, 'don_confiao/index.html')


def buy(request):
    if request.method == "POST":
        sale_form = PurchaseForm(request.POST)
        line_formset = SaleLineFormSet(request.POST)
        sale_summary_form = PurchaseSummaryForm(request.POST)
        forms_are_valid = all([
            sale_form.is_valid(),
            line_formset.is_valid(),
            sale_summary_form.is_valid()
        ])
        payment_method = request.POST.get('payment_method')
        valid_payment_methods = [PaymentMethods.CASH]
        valid_payment_method = payment_method in valid_payment_methods
        if forms_are_valid:
            with transaction.atomic():
                sale = sale_form.save()
                line_formset.instance = sale
                line_formset.save()
                Payment.total_payment_from_sale(
                    payment_method,
                    sale
                )
            return HttpResponseRedirect("compras")
    else:
        sale_form = PurchaseForm()
        line_formset = SaleLineFormSet()
        sale_summary_form = PurchaseSummaryForm()
    return render(
        request,
        'don_confiao/purchase.html',
        {
            'sale_form': sale_form,
            'linea_formset': line_formset,
            'summary_form': sale_summary_form,
            'list_products': json.dumps(Product.to_list(), cls=DecimalEncoder),
        }
    )


def purchases(request):
    purchases = Sale.objects.all()
    context = {
        "purchases": purchases,
    }
    return render(request, 'don_confiao/purchases.html', context)


def products(request):
    return JsonResponse(Product.to_list(), safe=False)


def import_products(request):
    if request.method == "POST":
        form = ImportProductsForm(request.POST, request.FILES)
        if form.is_valid():
            handle_import_products_file(request.FILES["csv_file"])
            return HttpResponseRedirect("productos")
    else:
        form = ImportProductsForm()
    return render(
        request,
        "don_confiao/import_products.html",
        {'form': form}
    )


def reconciliate_jar(request):
    summary = Payment.get_reconciliation_jar_summary()
    if request.method == 'POST':
        form = ReconciliationJarForm(request.POST)
        if form.is_valid():
            reconciliation = form.save()
            reconciliation.add_payments(summary.payments)
            reconciliation.clean()
            reconciliation.save()
            return HttpResponseRedirect('cuadres')
    else:
        form = ReconciliationJarForm()
    return render(
        request,
        "don_confiao/reconciliate_jar.html",
        {'summary': summary, 'form': form}
    )


def reconciliations(request):
    return HttpResponse('<h1>Reconciliaciones</h1>')

def purchase_summary(request, id):
    purchase = Sale.objects.get(pk=id)
    return render(
        request,
        "don_confiao/purchase_summary.html",
        {
            "purchase": purchase
        }
    )


def _categories_from_csv_string(categories_string, separator="&"):
    categories = categories_string.split(separator)
    clean_categories = [c.strip() for c in categories]
    return [_category_from_name(category) for category in clean_categories]


def _category_from_name(name):
    return ProductCategory.objects.get_or_create(name=name)[0]


def handle_import_products_file(csv_file):
    data = io.StringIO(csv_file.read().decode('utf-8'))
    reader = csv.DictReader(data, quotechar='"')
    for row in reader:
        product, created = Product.objects.update_or_create(
            name=row['producto'],
            defaults={
                'price': row['precio'],
                'measuring_unit': row['unidad']
            }
        )
        categories = _categories_from_csv_string(row["categorias"])
        product.categories.clear()
        for category in categories:
            product.categories.add(category)


def exportar_ventas_para_tryton(request):
    tryton_sales_header = [
        "Tercero",
        "Dirección de facturación",
        "Dirección de envío",
        "Descripción",
        "Referencia",
        "Fecha venta",
        "Plazo de pago",
        "Almacén",
        "Moneda",
        "Líneas/Producto",
        "Líneas/Cantidad",
        "Líneas/Precio unitario",
        "Líneas/Unidad",
        "Empresa",
        "Tienda",
        "Terminal de venta",
        "Autorecogida",
        "Comentario"
    ]

    if request.method == "GET":
        response = HttpResponse(content_type='text/csv')
        response['Content-Disposition'] = "attachment; filename=sales.csv"
        writer = csv.writer(response)
        writer.writerow(tryton_sales_header)

        sales = Sale.objects.all()

        for sale in sales:
            sale_lines = SaleLine.objects.filter(sale=sale.id)
            if not sale_lines:
                continue
            lines = []
            first_sale_line = sale_lines[0]
            customer_info = [sale.customer.name] * 3 + [sale.description] * 2
            first_line = customer_info + [
                sale.date,
                "Contado",
                "Almacén",
                "Peso colombiano",
                first_sale_line.product.name,
                first_sale_line.quantity,
                "Unidad",
                first_sale_line.unit_price,
                "TIENDA LA ILUSIÓN",
                "Tienda La Ilusion",
                "La Ilusion",
                True,
                sale.description]
            lines.append(first_line)
            for line in sale_lines[1:]:
                lines.append([""]*9+[
                    line.product.name,
                    line.quantity,
                    line.unit_price,
                    "Unidad"]+[""]*5)
            for row in lines:
                writer.writerow(row)

        return response


class ProductListView(ListView):
    model = Product
    template_model = 'don_confiao/product_list.html'

    def get_queryset(self):
        name = self.request.GET.get('name')
        if name:
            return Product.objects.filter(name__icontains=name)
        return Product.objects.all()