import re
import time
import base64

from django.contrib.auth import authenticate, login
from django.contrib.auth.models import User
from django.core.files.base import ContentFile
from django.db import transaction
from django.db.models import Q

from rest_framework import status
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from rest_framework_simplejwt.tokens import RefreshToken

from .models import Company, Customer, Product, Invoice, InvoiceItem



from django.contrib.auth.models import User
from django.contrib.auth import authenticate, login
from rest_framework.response import Response
from rest_framework import status
from rest_framework.views import APIView
from django.core.exceptions import ObjectDoesNotExist
from rest_framework_simplejwt.tokens import RefreshToken
import re  # For basic email validation
# from twilio.rest import Client as TwilioClient # 💡 Maru Peyaridhal!


from decimal import Decimal, InvalidOperation, ROUND_HALF_UP
from .models import Company, Customer, Product, Invoice, InvoiceItem
# from .models import Profiles  # uncomment / adjust import to match your app
TWO_PLACES = Decimal('0.01')


def ok(data=None, message=None, code=status.HTTP_200_OK):
    return Response({
        "status": {"code": code, "response": "success"},
        "error": None,
        **({"message": message} if message else {}),
        "data": data,
    }, status=code)


def fail(message, code=status.HTTP_400_BAD_REQUEST):
    return Response({
        "status": {"code": code, "response": "failed"},
        "error": True,
        "message": message,
    }, status=code)


def to_decimal(value, field_name):
    """
    Validate + coerce a value into a Decimal, raising a clear message on bad
    input. Goes through str() first so binary floating-point artifacts
    (e.g. 0.1 + 0.2 != 0.3) never leak into money fields.
    """
    if value is None or value == '':
        raise ValueError(f"'{field_name}' is required.")
    try:
        return Decimal(str(value))
    except (InvalidOperation, ValueError, TypeError):
        raise ValueError(f"'{field_name}' must be a valid number.")


def q2(value):
    """Round a Decimal to exactly 2 places using standard rounding (not banker's)."""
    return Decimal(value).quantize(TWO_PLACES, rounding=ROUND_HALF_UP)


# ============================================================ LOGIN =======
class LoginAPIView(APIView):
    """
    Accepts either a username or an email in `username`, plus `password`.
    `fcm_token` (optional) is stored against the profile for push notifications —
    it is intentionally NOT written into `pincode`; that was a bug in the
    previous version. Adjust the field name below to match your Profile model.
    """

    def post(self, request):
        data = request.data
        username_or_email = (data.get("username") or "").strip()
        password = data.get("password")
        fcm_token = data.get("fcm_token")

        if not username_or_email or not password:
            return fail("Username/email and password are required.", status.HTTP_400_BAD_REQUEST)

        is_email = re.match(r"[^@]+@[^@]+\.[^@]+", username_or_email)

        if is_email:
            try:
                matched = User.objects.get(email__iexact=username_or_email)
                username_to_auth = matched.username
            except User.DoesNotExist:
                return fail("Invalid username or password.", status.HTTP_401_UNAUTHORIZED)
        else:
            username_to_auth = username_or_email

        user = authenticate(request, username=username_to_auth, password=password)

        if user is None:
            return fail("Invalid username or password.", status.HTTP_401_UNAUTHORIZED)

        if not user.is_active:
            return fail("This account has been disabled.", status.HTTP_403_FORBIDDEN)

        login(request, user)
        token = RefreshToken.for_user(user)

        profile_photo = None
        phone = None
        role = None

        # Wire this up to your actual Profile model / related_name.
        # Example:
        # try:
        #     profile = Profiles.objects.get(user_id=user.id)
        #     if fcm_token:
        #         profile.fcm_token = fcm_token
        #         profile.save(update_fields=["fcm_token"])
        #     profile_photo = request.build_absolute_uri(profile.profiles.url) if profile.profiles else None
        #     phone = profile.phone
        #     role = profile.role
        # except Profiles.DoesNotExist:
        #     pass

        return ok({
            "name": user.username,
            "id": user.id,
            "username": user.username,
            "email": user.email,
            "isSuper": user.is_superuser,
            "refresh": str(token),
            "token": str(token.access_token),
            "profile": profile_photo,
            "companyname": "loop",
            "phone": phone,
            "role": role,
        }, message="Login success")


# ============================================================ COMPANY =====
class CompanyAPIView(APIView):
    permission_classes = (IsAuthenticated,)

    def _handle_logo(self, request, data):
        if 'logo' in request.FILES:
            return request.FILES['logo']

        logo_base64 = data.get('logo_base64')
        logo_filename = data.get('logo_filename', f'logo_{int(time.time())}.jpg')

        if logo_base64:
            try:
                if ',' in logo_base64:
                    logo_base64 = logo_base64.split(',')[1]
                logo_base64 = logo_base64.strip()
                image_data = base64.b64decode(logo_base64)
                return ContentFile(image_data, name=logo_filename)
            except Exception:
                return None
        return None

    def _serialize(self, request, company, row=None):
        payload = {
            'id': company.id,
            'company_name': company.company_name,
            'address': company.address,
            'mobile': company.mobile,
            'email': company.email,
            'gst_number': company.gst_number,
            'bank_details': company.bank_details,
            'dealers_in': company.dealers_in,
            'invoice_terms': company.invoice_terms,
            'logo': request.build_absolute_uri(company.logo.url) if company.logo else None,
        }
        if row is not None:
            payload['row'] = row
        return payload

    def _validate(self, data, partial=False):
        errors = {}
        company_name = data.get('company_name')
        if not partial and not (company_name and str(company_name).strip()):
            errors['company_name'] = 'Company name is required.'

        email = data.get('email')
        if email and not re.match(r'^[^@\s]+@[^@\s]+\.[^@\s]+$', str(email)):
            errors['email'] = 'Enter a valid email address.'

        mobile = data.get('mobile')
        if mobile and not re.match(r'^[0-9+\-\s]{7,15}$', str(mobile)):
            errors['mobile'] = 'Enter a valid mobile number.'

        return errors

    def get(self, request, id=None):
        if id is not None:
            try:
                company = Company.objects.get(id=id)
            except Company.DoesNotExist:
                return fail("No company found", status.HTTP_404_NOT_FOUND)
            return ok(self._serialize(request, company))

        search = request.query_params.get('search', '').strip()
        qs = Company.objects.all().order_by('-created_at')
        if search:
            qs = qs.filter(
                Q(company_name__icontains=search)
                | Q(gst_number__icontains=search)
                | Q(mobile__icontains=search)
                | Q(email__icontains=search)
            )
        data_list = [self._serialize(request, c, row=i) for i, c in enumerate(qs, 1)]
        return ok(data_list)

    def post(self, request):
        data = request.data
        errors = self._validate(data)
        if errors:
            return fail(errors, status.HTTP_400_BAD_REQUEST)

        logo = self._handle_logo(request, data)
        try:
            company = Company.objects.create(
                company_name=data.get('company_name'),
                address=data.get('address'),
                mobile=data.get('mobile'),
                email=data.get('email'),
                gst_number=data.get('gst_number'),
                bank_details=data.get('bank_details'),
                dealers_in=data.get('dealers_in'),
                invoice_terms=data.get('invoice_terms') or None,
                logo=logo,
            )
            return ok(self._serialize(request, company), message="Company added successfully",
                       code=status.HTTP_201_CREATED)
        except Exception as e:
            return fail(str(e))

    def put(self, request, id):
        data = request.data
        try:
            company = Company.objects.get(id=id)
        except Company.DoesNotExist:
            return fail("No company found", status.HTTP_404_NOT_FOUND)

        errors = self._validate(data, partial=True)
        if errors:
            return fail(errors, status.HTTP_400_BAD_REQUEST)

        try:
            logo = self._handle_logo(request, data)
            company.company_name = data.get("company_name", company.company_name)
            company.address = data.get("address", company.address)
            company.mobile = data.get("mobile", company.mobile)
            company.email = data.get("email", company.email)
            company.gst_number = data.get("gst_number", company.gst_number)
            company.bank_details = data.get("bank_details", company.bank_details)
            company.dealers_in = data.get("dealers_in", company.dealers_in)
            company.invoice_terms = data.get("invoice_terms", company.invoice_terms)
            if logo:
                company.logo = logo
            company.save()
            return ok(self._serialize(request, company), message="Company updated successfully")
        except Exception as e:
            return fail(str(e))

    def delete(self, request, id):
        try:
            company = Company.objects.get(id=id)
        except Company.DoesNotExist:
            return fail("No company found", status.HTTP_404_NOT_FOUND)
        company.delete()
        return ok(message="Company deleted successfully")


# =========================================================== CUSTOMER =====
class CustomerAPIView(APIView):
    permission_classes = (IsAuthenticated,)

    def _serialize(self, request, customer, row=None):
        payload = {
            'id': customer.id,
            'name': customer.name,
            'address': customer.address,
            'gst_number': customer.gst_number,
            'mobile': customer.mobile,
        }
        if row is not None:
            payload['row'] = row
        return payload

    def _validate(self, data, partial=False):
        errors = {}
        name = data.get('name')
        if not partial and not (name and str(name).strip()):
            errors['name'] = 'Customer name is required.'
        mobile = data.get('mobile')
        if mobile and not re.match(r'^[0-9+\-\s]{7,15}$', str(mobile)):
            errors['mobile'] = 'Enter a valid mobile number.'
        return errors

    def get(self, request, id=None):
        if id is not None:
            try:
                customer = Customer.objects.get(id=id)
            except Customer.DoesNotExist:
                return fail("No customer found", status.HTTP_404_NOT_FOUND)
            return ok(self._serialize(request, customer))

        search = request.query_params.get('search', '').strip()
        qs = Customer.objects.all().order_by('-created_at')
        if search:
            qs = qs.filter(
                Q(name__icontains=search)
                | Q(gst_number__icontains=search)
                | Q(mobile__icontains=search)
            )
        data_list = [self._serialize(request, c, row=i) for i, c in enumerate(qs, 1)]
        return ok(data_list)

    def post(self, request):
        data = request.data
        errors = self._validate(data)
        if errors:
            return fail(errors, status.HTTP_400_BAD_REQUEST)
        try:
            customer = Customer.objects.create(
                name=data.get('name'),
                address=data.get('address'),
                gst_number=data.get('gst_number'),
                mobile=data.get('mobile'),
            )
            return ok(self._serialize(request, customer), message="Customer added successfully",
                       code=status.HTTP_201_CREATED)
        except Exception as e:
            return fail(str(e))

    def put(self, request, id):
        data = request.data
        try:
            customer = Customer.objects.get(id=id)
        except Customer.DoesNotExist:
            return fail("No customer found", status.HTTP_404_NOT_FOUND)

        errors = self._validate(data, partial=True)
        if errors:
            return fail(errors, status.HTTP_400_BAD_REQUEST)

        try:
            customer.name = data.get("name", customer.name)
            customer.address = data.get("address", customer.address)
            customer.gst_number = data.get("gst_number", customer.gst_number)
            customer.mobile = data.get("mobile", customer.mobile)
            customer.save()
            return ok(self._serialize(request, customer), message="Customer updated successfully")
        except Exception as e:
            return fail(str(e))

    def delete(self, request, id):
        try:
            customer = Customer.objects.get(id=id)
        except Customer.DoesNotExist:
            return fail("No customer found", status.HTTP_404_NOT_FOUND)
        if customer.invoices.exists():
            return fail("This customer has invoices attached and can't be deleted.",
                        status.HTTP_400_BAD_REQUEST)
        customer.delete()
        return ok(message="Customer deleted successfully")


# ============================================================ PRODUCT =====
class ProductAPIView(APIView):
    permission_classes = (IsAuthenticated,)

    def _serialize(self, request, product, row=None):
        payload = {
            'id': product.id,
            'name': product.name,
            'hsn_code': product.hsn_code,
            'default_rate': str(product.default_rate),
            'unit': product.unit,
        }
        if row is not None:
            payload['row'] = row
        return payload

    def _validate(self, data, partial=False):
        errors = {}
        name = data.get('name')
        if not partial and not (name and str(name).strip()):
            errors['name'] = 'Product name is required.'
        rate = data.get('default_rate')
        if rate not in (None, ''):
            try:
                if float(rate) < 0:
                    errors['default_rate'] = 'Default rate cannot be negative.'
            except (TypeError, ValueError):
                errors['default_rate'] = 'Default rate must be a valid number.'
        return errors

    def get(self, request, id=None):
        if id is not None:
            try:
                product = Product.objects.get(id=id)
            except Product.DoesNotExist:
                return fail("No product found", status.HTTP_404_NOT_FOUND)
            return ok(self._serialize(request, product))

        search = request.query_params.get('search', '').strip()
        qs = Product.objects.all().order_by('-created_at')
        if search:
            qs = qs.filter(Q(name__icontains=search) | Q(hsn_code__icontains=search))
        data_list = [self._serialize(request, p, row=i) for i, p in enumerate(qs, 1)]
        return ok(data_list)

    def post(self, request):
        data = request.data
        errors = self._validate(data)
        if errors:
            return fail(errors, status.HTTP_400_BAD_REQUEST)
        try:
            product = Product.objects.create(
                name=data.get('name'),
                hsn_code=data.get('hsn_code'),
                default_rate=data.get('default_rate') or 0,
                unit=data.get('unit', 'Kg'),
            )
            return ok(self._serialize(request, product), message="Product added successfully",
                       code=status.HTTP_201_CREATED)
        except Exception as e:
            return fail(str(e))

    def put(self, request, id):
        data = request.data
        try:
            product = Product.objects.get(id=id)
        except Product.DoesNotExist:
            return fail("No product found", status.HTTP_404_NOT_FOUND)

        errors = self._validate(data, partial=True)
        if errors:
            return fail(errors, status.HTTP_400_BAD_REQUEST)

        try:
            product.name = data.get("name", product.name)
            product.hsn_code = data.get("hsn_code", product.hsn_code)
            product.default_rate = data.get("default_rate", product.default_rate)
            product.unit = data.get("unit", product.unit)
            product.save()
            return ok(self._serialize(request, product), message="Product updated successfully")
        except Exception as e:
            return fail(str(e))

    def delete(self, request, id):
        try:
            product = Product.objects.get(id=id)
        except Product.DoesNotExist:
            return fail("No product found", status.HTTP_404_NOT_FOUND)
        if product.invoice_items.exists():
            return fail("This product is used in invoices and can't be deleted.",
                        status.HTTP_400_BAD_REQUEST)
        product.delete()
        return ok(message="Product deleted successfully")


# ============================================================ INVOICE =====
class InvoiceAPIView(APIView):
    permission_classes = (IsAuthenticated,)

    def _serialize(self, request, invoice, row=None):
        items = [
            {
                'id': item.id,
                'product': item.product_id,
                'product_name': item.product.name,
                'hsn_code': item.product.hsn_code,
                'quantity': str(item.quantity),
                'rate': str(item.rate),
                'amount': str(item.amount),
            }
            for item in invoice.items.all()
        ]
        payload = {
            'id': invoice.id,
            'invoice_number': invoice.invoice_number,
            'invoice_date': invoice.invoice_date,
            'customer': invoice.customer_id,
            'customer_name': invoice.customer.name,
            'customer_gst_number': invoice.customer.gst_number,
            'customer_address': invoice.customer.address,
            'eway_bill_no': invoice.eway_bill_no,
            'eway_bill_date': invoice.eway_bill_date,
            'vehicle_no': invoice.vehicle_no,
            'subtotal': str(invoice.subtotal),
            'cgst': str(invoice.cgst),
            'sgst': str(invoice.sgst),
            'igst': str(invoice.igst),
            'round_off': str(invoice.round_off),
            'grand_total': str(invoice.grand_total),
            'items': items,
        }
        if row is not None:
            payload['row'] = row
        return payload

    def _validate_items(self, items_data):
        """Returns (cleaned_items, error_message_or_None). Also rejects duplicate products."""
        if not items_data:
            return None, "Add at least one line item."

        cleaned = []
        seen_products = set()
        for idx, it in enumerate(items_data, 1):
            product_id = it.get('product')
            if not product_id:
                return None, f"Line {idx}: select a product."
            if str(product_id) in seen_products:
                return None, f"Line {idx}: this product is already added to the invoice."
            seen_products.add(str(product_id))

            if not Product.objects.filter(id=product_id).exists():
                return None, f"Line {idx}: product not found."

            try:
                qty = to_decimal(it.get('quantity', 0), 'quantity')
                rate = to_decimal(it.get('rate', 0), 'rate')
            except ValueError as e:
                return None, f"Line {idx}: {e}"

            if qty <= 0:
                return None, f"Line {idx}: quantity must be greater than 0."
            if rate < 0:
                return None, f"Line {idx}: rate cannot be negative."

            cleaned.append({'product_id': product_id, 'quantity': qty, 'rate': rate})

        return cleaned, None

    def get(self, request, id=None):
        if id is not None:
            try:
                invoice = Invoice.objects.get(id=id)
            except Invoice.DoesNotExist:
                return fail("No invoice found", status.HTTP_404_NOT_FOUND)
            return ok(self._serialize(request, invoice))

        search = request.query_params.get('search', '').strip()
        qs = Invoice.objects.all().order_by('-created_at')
        if search:
            qs = qs.filter(
                Q(invoice_number__icontains=search) | Q(customer__name__icontains=search)
            )
        data_list = [self._serialize(request, i, row=r) for r, i in enumerate(qs, 1)]
        return ok(data_list)

    def _validate_tax_fields(self, cgst, sgst, igst, round_off):
        if cgst < 0:
            return "CGST cannot be negative."
        if sgst < 0:
            return "SGST cannot be negative."
        if igst < 0:
            return "IGST cannot be negative."
        # Round off exists only to absorb paisa-level rounding — cap its
        # magnitude so a typo can't silently swing the invoice total.
        if abs(round_off) >= 1:
            return "Round off must be a small adjustment (less than ₹1)."
        return None

    def post(self, request):
        data = request.data
        invoice_number = (data.get('invoice_number') or '').strip()
        customer_id = data.get('customer')
        items_data = data.get('items', [])

        if not invoice_number:
            return fail("Invoice number is required.")
        if Invoice.objects.filter(invoice_number=invoice_number).exists():
            return fail(f"Invoice number '{invoice_number}' is already in use.")
        if not customer_id or not Customer.objects.filter(id=customer_id).exists():
            return fail("A valid customer is required.")
        if not data.get('invoice_date'):
            return fail("Invoice date is required.")

        cleaned_items, err = self._validate_items(items_data)
        if err:
            return fail(err)

        try:
            cgst = to_decimal(data.get('cgst') or 0, 'cgst')
            sgst = to_decimal(data.get('sgst') or 0, 'sgst')
            igst = to_decimal(data.get('igst') or 0, 'igst')
            round_off = to_decimal(data.get('round_off') or 0, 'round_off')
        except ValueError as e:
            return fail(str(e))

        tax_err = self._validate_tax_fields(cgst, sgst, igst, round_off)
        if tax_err:
            return fail(tax_err)

        try:
            with transaction.atomic():
                subtotal = q2(sum((i['quantity'] * i['rate'] for i in cleaned_items), Decimal('0')))
                grand_total = q2(subtotal + cgst + sgst + igst + round_off)

                if grand_total < 0:
                    return fail("Invoice total cannot be negative — check the entered amounts.")

                invoice = Invoice.objects.create(
                    invoice_number=invoice_number,
                    invoice_date=data.get('invoice_date'),
                    customer_id=customer_id,
                    eway_bill_no=data.get('eway_bill_no'),
                    eway_bill_date=data.get('eway_bill_date') or None,
                    vehicle_no=data.get('vehicle_no'),
                    subtotal=subtotal,
                    cgst=q2(cgst),
                    sgst=q2(sgst),
                    igst=q2(igst),
                    round_off=q2(round_off),
                    grand_total=grand_total,
                )
                InvoiceItem.objects.bulk_create([
                    InvoiceItem(
                        invoice=invoice,
                        product_id=i['product_id'],
                        quantity=i['quantity'],
                        rate=i['rate'],
                        amount=q2(i['quantity'] * i['rate']),
                    )
                    for i in cleaned_items
                ])
            return ok(self._serialize(request, invoice), message="Invoice created successfully",
                       code=status.HTTP_201_CREATED)
        except Exception as e:
            return fail(str(e))

    def put(self, request, id):
        data = request.data
        try:
            invoice = Invoice.objects.get(id=id)
        except Invoice.DoesNotExist:
            return fail("No invoice found", status.HTTP_404_NOT_FOUND)

        new_number = data.get("invoice_number")
        if new_number and new_number != invoice.invoice_number:
            if Invoice.objects.filter(invoice_number=new_number).exclude(id=id).exists():
                return fail(f"Invoice number '{new_number}' is already in use.")

        cleaned_items = None
        if "items" in data:
            cleaned_items, err = self._validate_items(data.get("items", []))
            if err:
                return fail(err)

        try:
            cgst = to_decimal(data.get('cgst', invoice.cgst), 'cgst')
            sgst = to_decimal(data.get('sgst', invoice.sgst), 'sgst')
            igst = to_decimal(data.get('igst', invoice.igst), 'igst')
            round_off = to_decimal(data.get('round_off', invoice.round_off), 'round_off')
        except ValueError as e:
            return fail(str(e))

        tax_err = self._validate_tax_fields(cgst, sgst, igst, round_off)
        if tax_err:
            return fail(tax_err)

        # Validate the prospective total BEFORE touching the database — a
        # `return` inside transaction.atomic() commits rather than rolling
        # back (only an exception rolls back), so any check that can fail
        # must happen first, especially since we delete existing line items.
        prospective_subtotal = (
            q2(sum((i['quantity'] * i['rate'] for i in cleaned_items), Decimal('0')))
            if cleaned_items is not None else invoice.subtotal
        )
        prospective_grand_total = q2(prospective_subtotal + cgst + sgst + igst + round_off)
        if prospective_grand_total < 0:
            return fail("Invoice total cannot be negative — check the entered amounts.")

        try:
            with transaction.atomic():
                invoice.invoice_number = new_number or invoice.invoice_number
                invoice.invoice_date = data.get("invoice_date", invoice.invoice_date)
                invoice.eway_bill_no = data.get("eway_bill_no", invoice.eway_bill_no)
                invoice.eway_bill_date = data.get("eway_bill_date", invoice.eway_bill_date) or None
                invoice.vehicle_no = data.get("vehicle_no", invoice.vehicle_no)
                if data.get("customer"):
                    if not Customer.objects.filter(id=data["customer"]).exists():
                        raise ValueError("A valid customer is required.")
                    invoice.customer_id = data.get("customer")

                if cleaned_items is not None:
                    invoice.items.all().delete()
                    InvoiceItem.objects.bulk_create([
                        InvoiceItem(
                            invoice=invoice,
                            product_id=i['product_id'],
                            quantity=i['quantity'],
                            rate=i['rate'],
                            amount=q2(i['quantity'] * i['rate']),
                        )
                        for i in cleaned_items
                    ])
                    invoice.subtotal = prospective_subtotal

                invoice.cgst = q2(cgst)
                invoice.sgst = q2(sgst)
                invoice.igst = q2(igst)
                invoice.round_off = q2(round_off)
                invoice.grand_total = q2(
                    invoice.subtotal + invoice.cgst + invoice.sgst + invoice.igst + invoice.round_off
                )
                invoice.save()

            return ok(self._serialize(request, invoice), message="Invoice updated successfully")
        except ValueError as e:
            return fail(str(e))
        except Exception as e:
            return fail(str(e))

    def delete(self, request, id):
        try:
            invoice = Invoice.objects.get(id=id)
        except Invoice.DoesNotExist:
            return fail("No invoice found", status.HTTP_404_NOT_FOUND)
        invoice.delete()
        return ok(message="Invoice deleted successfully")




def send_otp_email(email, otp):
    subject = 'Your One-Time  (OTP) for Verification'
    message = f'''Dear User,

    Your One-Time  (OTP) for verification is:

    {otp}

    Please enter this code to proceed. This OTP is valid for the next 1 minutes.

    If you did not request this code, please ignore this email.

    Thank you,  
    Pearlcon Technologies LLP
    https://pearlcons.com
    '''
    try:
        send_mail(
            subject,
            message,
            settings.DEFAULT_FROM_EMAIL,
            [email],
            fail_silently=False,
        )
    except Exception as e:
        print(f"Error sending email: {e}")
def send_otp_emails(email, otp):
   
    subject = 'Your One-Time  (OTP) for Verification'
    message = f'''Dear User,

    Your One-Time  (OTP) for verification is:

    {otp}

    Please enter this code to proceed. This OTP is valid for the next 1 minutes.

    If you did not request this code, please ignore this email.

    Thank you,  
    Pearlcon Technologies LLP
    https://pearlcons.com
        '''
    try:
        send_mail(
            subject,
            message,
            settings.DEFAULT_FROM_EMAIL,
            [email],
            fail_silently=False,
        )
    except Exception as e:
        print(f"Error sending email: {e}")

        
from django.contrib.auth import get_user_model
User = get_user_model()

class SendotpAPIView(APIView):
    def post(self, request):
        data = request.data
        try:
            email = data.get('params', {}).get('email', None)
            print('Received email:', email)

            # ✅ Step 1: Check if email exists in registered users
            if not User.objects.filter(email=email).exists():
                return Response({
                    "status": {"code": status.HTTP_404_NOT_FOUND, "response": "Email not found"},
                    "error": True,
                    "message": "Email not registered"
                })

            # ✅ Step 2: Create OTP record and send OTP
            user = Otp.objects.create(email=email)
            otp = get_random_string(length=6, allowed_chars='1234567890')
            user.otp = otp
            user.otp_created_at = timezone.now()
            user.save()

            threading.Thread(target=send_otp_email, args=(email, otp)).start()

            return Response({
                "status": {"code": status.HTTP_200_OK, "response": "Success"},
                "error": None,
                "data": {"email": email}
            })
        except Exception as e:
            print("Error:", e)
            return Response({
                "status": {"code": status.HTTP_500_INTERNAL_SERVER_ERROR, "response": "Internal Server Error"},
                'error': True,
                "message": str(e)
            })


class SendotpsAPIView(APIView):
    def post(self, request):
        data = request.data
        try:
            email = data.get('email', None)
            print('Received email:', email)

            # If this is registration
            if User.objects.filter(email=email).exists():
                return Response({
                    "status": {"code": status.HTTP_409_CONFLICT, "response": "Email already registered"},
                    "error": True,
                    "message": "This email is already registered. Please use another email."
                })

            otp = get_random_string(length=6, allowed_chars='1234567890')
            user = Otp.objects.create(email=email, otp=otp, otp_created_at=timezone.now())

            threading.Thread(target=send_otp_emails, args=(email, otp)).start()

            return Response({
                "status": {"code": status.HTTP_200_OK, "response": "Success"},
                "error": None,
                "data": {"email": email}
            })
        except Exception as e:
            return Response({
                "status": {"code": status.HTTP_500_INTERNAL_SERVER_ERROR, "response": "Internal Server Error"},
                'error': True,
                "message": str(e)
            })

from datetime import timedelta
from django.utils import timezone

class VerifyotpAPIView(APIView):
    def get(self, request):
        email = request.query_params.get('email')
        otp_entered = request.query_params.get('otp')

        try:
            user_otp = Otp.objects.filter(email=email).latest('otp_created_at')

            # Expiry time check (30 seconds)
            expiration_time = user_otp.otp_created_at + timedelta(seconds=60)
            if timezone.now() > expiration_time:
                return Response({
                    "status": 401,
                    "message": "OTP expired. Please request a new one.",
                    "error": True
                }, status=status.HTTP_200_OK) 

            if otp_entered == user_otp.otp:
                return Response({
                    "status": 200,
                    "message": "OTP Verified",
                    "error": False
                }, status=status.HTTP_200_OK)
            else:
                return Response({
                    "status": 400,
                    "message": "Invalid OTP",
                    "error": True
                }, status=status.HTTP_200_OK)

        except Otp.DoesNotExist:
            return Response({
                "status": 404,
                "message": "OTP not found",
                "error": True
            }, status=status.HTTP_200_OK)




    def delete(self, request, id):
        if id is not None:
            try:
                profile = Profiles.objects.get(user_id=id)

                # Delete the image file from storage (optional)
                if profile.profiles:  # replace 'image' with your actual image field name
                    profile.profiles.delete(save=False)  # Deletes the file from MEDIA folder
                    profile.profiles = None
                    profile.save()

                return Response({
                    "status": {"code": status.HTTP_200_OK, "response": "success"},
                    "error": None,
                    "message": "Profile image deleted successfully"
                })

            except ObjectDoesNotExist:
                return Response({
                    "status": {"code": status.HTTP_404_NOT_FOUND, "response": "failed"},
                    "error": None,
                    "message": "Profile not found"
                })

        return Response({
            "status": {"code": status.HTTP_400_BAD_REQUEST, "response": "failed"},
            "error": "ID not provided",
            "message": "User ID is required"
        })




class ProfileupdateAPIView(APIView):
    
    permission_classes = (IsAuthenticated,)

    def get(self, request, **kwargs):
        id = kwargs.get('id')


        if id is not None:
            try:
                user = User.objects.get(id=id)
                company = Profiles.objects.get(user_id=user.id)
                if company.profiles and company.profiles.url != "../static/dummy.png":
                    pr = company.profiles.url
                else:
                    pr = "../static/dummy.png"

                data = {
                    'name': company.name,
                    'email': company.email,
                    'phone': company.phone,
                    'f_name': user.first_name,
                    'l_name': user.last_name,

                    'profile' : pr,
                    'id': user.id   
                }



                

                return Response({
                    "status": {"code": status.HTTP_200_OK, "response": "Success"},
                    "error": None,
                    "data": data
                })
            except ObjectDoesNotExist:
                return Response({
                    "status": {"code": status.HTTP_404_NOT_FOUND, "response": "Failed"},
                    'error': True,
                    "message": "Company not found"
                })

    def post(self, request):
        data = request.data
        try:


            pho = data.get("prof_photo")
            # name = data.get("username")

            take = Profiles.objects.get(user_id=request.user.id)
            take.profiles = pho

            take.save()
            # # Create User instance
            # van = User(username=name, email=email, password=hashed_password)
            # van.save()

           

            return Response({
                "status": {"code": status.HTTP_201_CREATED, "response": "success"},
                "error": None,
                "message": "Profile updated successfully"
            })

        except KeyError as e:
            return Response({
                "status": {"code": status.HTTP_400_BAD_REQUEST, "response": "failed"},
                "error": True,
                "message": f"Missing required field: {str(e)}"
            })
        except Exception as e:
            return Response({
                "status": {"code": status.HTTP_500_INTERNAL_SERVER_ERROR, "response": "failed"},
                "error": True,
                "message": f"An error occurred: {str(e)}"
            })


    def put(self, request, id):
        data = request.data
        # 1. போட்டோவை FILES-ல் இருந்து எடுக்கவும்
        photo = request.FILES.get('prof_photo') 
        
        try:
            mm = Profiles.objects.get(user_id=id)
            sd = User.objects.get(id=id)

            # 2. User டேபிள் அப்டேட் (get() பயன்படுத்துவது பாதுகாப்பானது)
            sd.username = data.get("first_name", sd.username)
            sd.first_name = data.get("first_names", sd.first_name)
            sd.last_name = data.get("last_name", sd.last_name)
            sd.email = data.get("email_id", sd.email)
            sd.save()

            # 3. Profiles டேபிள் அப்டேட்
            mm.email = data.get("email_id", mm.email)
            mm.phone = data.get("phone_no", mm.phone)
            mm.name = data.get("first_name", mm.name)

            # 4. இமேஜ் இருந்தால் மட்டும் அப்டேட் செய்யவும்
            if photo:
                mm.profiles = photo
            
            mm.save()

            return Response({
                "status": {"code": status.HTTP_200_OK, "response": "success"},
                "error": None,
                "message": "User updated successfully"
            })

        except ObjectDoesNotExist:
            return Response({
                "status": {"code": status.HTTP_404_NOT_FOUND, "response": "failed"},
                "error": True,
                "message": "User not found"
            })




class RegisterAPIView(APIView):
    def get(self, request, **kwargs):
        id = kwargs.get('id')


        if id is not None:
            try:
                student = Profiles.objects.get(user_id=id)
                data = {
                    'id': student.user_id,
                    'username': student.name,
                    'phone': student.phone,
                    'password': student.password,
                    'email': student.email,
                    'role': student.role,

                    'status': student.status,
                    # Photo URL-ஐ எடுக்க (உதாரணமாக: http://127.0.0.1:8000/media/students/abc.jpg)
                    'profile_photo': request.build_absolute_uri(student.profiles.url) if student.profiles else None
                }


                return Response({
                    "status": {"code": status.HTTP_200_OK, "response": "success"},
                    "error": None,
                    "data": data
                })
            except Student.DoesNotExist:
                return Response({
                    "status": {"code": status.HTTP_404_NOT_FOUND, "response": "failed"},
                    "error": True,
                    "message": "No student found",
                })
        else:
            try:
                employees = Profiles.objects.filter(role__in=[2, 3,0]).order_by('-created_at')
                employee_list = []
                for index, student in enumerate(employees, 1):
                    employee_list.append({
                        'row': index,
                        'id': student.user_id,
                        'employeeName': student.name,
                        'email': student.email,
                        'phone': student.phone,
                        'status': student.status,
                        'role': student.role,

                        'photo': request.build_absolute_uri(student.profiles.url) if student.profiles else None
                    })

                return Response({
                    "status": {"code": status.HTTP_200_OK, "response": "success"},
                    "error": None,
                    "data": employee_list
                })
            except Exception as e:
                return Response({
                    "status": {"code": status.HTTP_400_BAD_REQUEST, "response": "failed"},
                    "error": True,
                    "message": str(e),
                })
    def post(self, request):
        data = request.data
        # ஆப்பில் இருந்து "profile_photo" என்று அனுப்புகிறோம், அதை இங்கே எடுக்கிறோம்
        photo = request.FILES.get('profile_photo') 


        try:
            username = data.get('username')
            email = data.get('email')
            phone = data.get('phone')
            password = data.get('password')
            role = data.get('role')


            # 1. User உருவாக்குதல்
            hashed_password = make_password(password)
            van = User.objects.create(
                username=username, 
                email=email, 
                password=hashed_password
            )

            # 2. Profile உருவாக்குதல்
            photo = request.FILES.get('profile_photo') 

            profile = Profiles.objects.create(
                name=username,
                email=email,
                phone=phone,
                role=role,
                user_id=van.id,
                password=password,
                profiles=photo  # 👈 உங்கள் Database Column பெயர் 'profiles' என்றால் இது சரி
            )

            return Response({
                "status": {"code": 201, "response": "success"},
                "error": None,
                "message": "Employee created successfully",
            }, status=status.HTTP_201_CREATED)

        except Exception as e:
            return Response({
                "status": {"code": 400, "response": "failed"},
                "error": True,
                "message": f"Error: {str(e)}"
        }, status=status.HTTP_400_BAD_REQUEST)


    
    def put(self, request, id):
        data = request.data
        # ஆப்பில் இருந்து "profile_photo" என்று அனுப்புகிறோம், அதை இங்கே எடுக்கிறோம்
        photo = request.FILES.get('profile_photo') 
        
        try:
                photo = request.FILES.get('profile_photo') 

                username = data.get('username')
                email = data.get('email')
                phone = data.get('phone')
                password = data.get('password')
                role = data.get('role')

                mm = Profiles.objects.get(user_id=id)
                sd = User.objects.get(id=id)

                mm.name = username
                mm.email = email
                mm.phone = phone
                mm.role = role
                mm.password = password

                if photo:
                    mm.profiles = photo
                mm.save()
                passes = make_password(password) 
                sd.username = username
                sd.email = email
                sd.password = passes
                sd.save()

                return Response({
                    "status": {"code": status.HTTP_201_CREATED, "response": "success"},
                    "error": None,
                    "message": "User updated successfully"
                })
        except ObjectDoesNotExist:
                return Response({
                    "status": {"code": status.HTTP_400_BAD_REQUEST, "response": "failed"},
                    "error": True,
                    "message": "Something went wrong"
                })

    def delete(self,  *args, **kwargs):
        company_id = kwargs.get('id')

        try:

            pr  = Profiles.objects.get(user_id =company_id)
            pr.delete()
            company = User.objects.get(id=company_id)
            company.delete()

            return Response({
                "status": {"code": status.HTTP_200_OK, "response": "success"},
                "error": None,
                "message": "Company deleted successfully"
            })
        except ObjectDoesNotExist:
            return Response({
                "status": {"code": status.HTTP_404_NOT_FOUND, "response": "failed"},
                "error": True,
                "message": "No data found"
            })









    

