from django.shortcuts import render
from django.contrib import messages
# Create your views here.
from django_filters.views import FilterView
from django.urls import reverse_lazy, reverse
from django.views.generic import (
    ListView,
    DetailView,
    CreateView,
    UpdateView,
    DeleteView,
)
from django.core.paginator import Paginator
from core.models import MgMasterView, VMasterView, BelMasterView, EMasterView
from pprint import pprint

class ConfigurableCRUDView:
    model = None
    list_template_name = None
    detail_template_name = None
    form_template_name = None
    confirm_delete_template_name = None
    fields = '__all__'  # Default to all fields
    paginate_by = 50
    filterset_class = None
    page_title = "Page Title"
    create_url_name = None
    update_url_name = None
    delete_url_name = None
    list_url_name = None
    config_fields = "all"  # "all" or a list of field names to display
    config_field_orders = []  # Fields to display first
    config_excludes = []  # Fields to exclude

    config_readonly_fields = []  # Fields that should be read-only in update view

    config_edit_fields = "__all__"  # "all" or a list of field names to display
    ordering = None
    form_class = None

    def get_fields(self):
        """
        Dynamically generate the fields to be displayed in the list view.
        - Includes all fields if `config_fields` is set to "all".
        - Respects `config_field_orders` and `config_excludes`.
        Returns field instances instead of field names.
        """
        pprint("get_fields")
        model_fields = {f.name: f for f in self.model._meta.get_fields()}

        # Filter based on `config_fields` configuration
        fields = []
        if self.config_fields != "all":
            fields = [model_fields[f] for f in self.config_fields if f in model_fields]
        else:
            fields = list(model_fields.values())
        # pprint("------------------------")
        # pprint(f"fields = {fields}")

        # Exclude fields specified in `config_excludes`
        fields = [f for f in fields if f.name not in self.config_excludes]

        # Order fields based on `config_field_orders`
        ordered_fields = [f for f in fields if f.name in self.config_field_orders]
        remaining_fields = [f for f in fields if f.name not in self.config_field_orders]

        # Reorder fields to match the order specified in `config_field_orders`
        ordered_field_names = set(self.config_field_orders)
        ordered_fields.sort(key=lambda f: self.config_field_orders.index(f.name) if f.name in ordered_field_names else len(ordered_field_names))
        return ordered_fields + remaining_fields


    def get_breadcrumbs(self, view_type, obj=None):
        """
        Generate breadcrumbs dynamically based on the view type.
        :param view_type: The type of view (list, create, update, detail, delete)
        :param obj: The current object (if applicable)
        :return: A list of breadcrumb dictionaries
        """
        breadcrumbs = [
            {'label': 'Dashboard', 'url': reverse('dashboard:index')},
            {'label': self.page_title, 'url': reverse(self.list_url_name)} if self.list_url_name else None,
        ]

        if view_type == 'create':
            breadcrumbs.append({'label': f'Create {self.model._meta.verbose_name}', 'url': None})
        elif view_type == 'update' and obj:
            breadcrumbs.append({'label': obj, 'url': reverse(self.update_url_name, kwargs={'pk': obj.pk})})
        elif view_type == 'detail' and obj:
            breadcrumbs.append({'label': f'Detail of {obj}', 'url': None})
        elif view_type == 'delete' and obj:
            breadcrumbs.append({'label': f'Delete {obj}', 'url': None})

        return [b for b in breadcrumbs if b]

    def get_list_view(self):
        class ListViewClass(FilterView, ListView):
            model = self.model
            template_name = self.list_template_name
            paginate_by = self.paginate_by
            filterset_class = self.filterset_class
            ordering = self.ordering

            def get_context_data(inner_self, **kwargs):
                context = super().get_context_data(**kwargs)
                fields = self.get_fields()
                context.update({
                    'fields': [f for f in fields],

                    # 'fields': [field for field in self.model._meta.get_fields()],
                    'page_title': self.page_title,
                    'list_url': self.list_url_name,
                    'create_url': self.create_url_name,
                    'update_url': self.update_url_name,
                    'delete_url': self.delete_url_name,
                    'bs': self.get_breadcrumbs('list'),
                })
                return context

        return ListViewClass

    def get_detail_view(self):
        class DetailViewClass(DetailView):
            model = self.model
            template_name = self.detail_template_name

            def get_context_data(inner_self, **kwargs):
                context = super().get_context_data(**kwargs)
                context.update({
                    'page_title': self.page_title,
                    'bs': self.get_breadcrumbs('detail'),
                })
                return context

        return DetailViewClass

    def get_create_view(self):
        class CreateViewClass(CreateView):
            model = self.model
            template_name = self.form_template_name
            fields = self.config_edit_fields
            form_class = self.form_class

            def form_valid(inner_self, form):
                response = super().form_valid(form)
                messages.success(inner_self.request, f"{self.model._meta.verbose_name} created successfully!")
                return response

            def get_success_url(inner_self):
                return reverse(self.update_url_name, kwargs={'pk': inner_self.object.pk})

            def get_context_data(inner_self, **kwargs):
                context = super().get_context_data(**kwargs)
                context.update({
                    'list_url_name': self.list_url_name,
                    'page_title': f"Create {self.model._meta.verbose_name}",
                    'bs': self.get_breadcrumbs('update', obj=inner_self.object),

                })
                return context

        return CreateViewClass

    def get_update_view(self):
        class UpdateViewClass(UpdateView):
            model = self.model
            template_name = self.form_template_name
            fields = self.config_edit_fields
            form_class = self.form_class
            
            def form_valid(inner_self, form):
                response = super().form_valid(form)
                messages.success(inner_self.request, f"{self.model._meta.verbose_name} updated successfully!")
                return response

            def get_form(inner_self, *args, **kwargs):
                """
                Customize the form to make specified fields read-only.
                """
                form = super().get_form(*args, **kwargs)
                for field_name in self.config_readonly_fields:
                    if field_name in form.fields:
                        form.fields[field_name].widget.attrs['readonly'] = True
                        form.fields[field_name].widget.attrs['style'] = 'background-color: #f9f9f9; cursor: not-allowed;'
                        form.fields[field_name].disabled = True  # Optional: Completely disable the field
                return form

            def get_success_url(inner_self):
                return reverse(self.update_url_name, kwargs={'pk': inner_self.object.pk})

            def get_context_data(inner_self, **kwargs):
                context = super().get_context_data(**kwargs)
                context.update({
                    'list_url_name': self.list_url_name,
                    'page_title': f"Update {self.model._meta.verbose_name}",
                    'bs': self.get_breadcrumbs('update', obj=inner_self.object),
                })
                return context

        return UpdateViewClass

    def get_delete_view(self):
        class DeleteViewClass(DeleteView):
            model = self.model
            template_name = self.confirm_delete_template_name
            success_url = reverse_lazy(self.list_url_name)

            def get_context_data(inner_self, **kwargs):
                context = super().get_context_data(**kwargs)
                context.update({
                    'list_url_name': self.list_url_name,
                    'page_title': f"Delete {self.model._meta.verbose_name}",
                    'bs': self.get_breadcrumbs('delete', obj=inner_self.object),
                })
                return context

        return DeleteViewClass

def queryFromMaster(lot_no):
    models = [MgMasterView, VMasterView, BelMasterView, EMasterView]
    value_to_filter = lot_no

    results = []

    for model in models:
        queryset = model.objects.filter(PRO2=value_to_filter)
        results.extend(queryset)
    return results

SHEET_NAMES = {
    'hardness_out': '1. Hardness Out',
    'hardness_out_in': '2.1 Hardness Out/In', 
    'hardness_out_in_4': '2.2 Hardness Out/In 4 Points', 
    'hardness_both_size': '3. Hardness Both Size',
    'dimension': '4.1 Dimension',
    'dimension_weight_warp': '4.2 Dimension/Weight/Warp',
    'dimension_app': '5.1 Dimension Appearance',
    'dimension_app_drawing': '5.2 Dimension Appearance + Drawing',
    'dimension_bal_weight': '6. Dimension Balance/Weight',
    'dim_bal_app_hard': '7.1 Dimension Balance/Appearance/Hardness',
    'dim_bal_app_hard_stamp': '7.2 Dimension Balance/Appearance/Hardness + Stamp',
    'dim_bal_app_rot_hard': '8. Dimension Balance/Appearance/Rotation/Hardness',
    'thickness_8_point': '9. Thickness 8 Points',
    'centering': '10. Centering',
}

def convert_mgt_to_mks(mgt_code: str) -> str:
    if not mgt_code:
        raise ValueError("MGT code cannot be empty")

    last_char = mgt_code[-1]

    if last_char.isdigit():
        # If last char is digit, code = -01
        base_part = mgt_code[:-1]
        suffix = "-01"
    elif last_char.isalpha():
        # A=1, B=2, ..., Z=26
        code = ord(last_char.upper()) - ord('A') + 1
        base_part = mgt_code[:-1]
        suffix = f"-{code:02d}"
    else:
        raise ValueError("Invalid last character in MGT code")

    return f"68-{base_part}{suffix}"