from django.contrib import admin
from .models import  OTT, OTTPlan, SkylinkPlan, OTTActivationLog, OTTAggregator,IptvRequest, SupportVideo, TVChannel,OTTPlanGroup
from django.utils.html import mark_safe
from django.utils.html import format_html
import json
from .models import JioHotstarCode
from import_export.admin import ImportExportModelAdmin
from .resources import JioHotstarCodeResource
from datetime import datetime, time
from django.template.response import TemplateResponse
import re
from collections import defaultdict
from django.urls import path
from django.db.models import Count
import pytz
from django.utils.timezone import is_naive
import colorsys

import csv
from django.http import HttpResponse
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from io import BytesIO
import base64
import random
import plotly.express as px
import plotly.graph_objects as go
import plotly.io as pio
from .models import CashfreePayment


# Admin configuration for the OTT model 
class OTTAdmin(admin.ModelAdmin):
    list_display = ('name', 'code', 'is_active', 'order_id', 'image_tag')  # Include order_id
    list_filter = ('is_active',)
    search_fields = ('name',)

    def image_tag(self, obj):
        if obj.image:
            return mark_safe(f'<img src="{obj.image.url}" width="100" />')
        return 'No Image'

    readonly_fields = ('image_tag',)

    fieldsets = (
        (None, {
            'fields': ('name', 'code', 'is_active', 'order_id', 'image', 'image_tag'),  # Added order_id and image_tag
        }),
    )

admin.site.register(OTT, OTTAdmin)

# Admin configuration for OTTAggregator model
class OTTAggregatorAdmin(admin.ModelAdmin):
    list_display = ('name', 'code', 'status')  # Display name, code, and status
    list_filter = ('status',)  # Filter by status (active/inactive)
    search_fields = ('name', 'code')  # Allow search by name or code
    list_editable = ('status',)  # Allow editing the status directly from the list view

admin.site.register(OTTAggregator, OTTAggregatorAdmin)

# Register the OTTPlanGroup model in the admin panel
class OTTPlanGroupAdmin(admin.ModelAdmin):
    list_display = ('name', 'group_code', 'platform_id', 'description')  # Columns to display in the list view
    search_fields = ('name', 'group_code', 'platform_id__name')  # Enable search by group name and platform name
    list_filter = ('platform_id',)  # Filter options by platform

admin.site.register(OTTPlanGroup, OTTPlanGroupAdmin)

# Admin configuration for the OTTPlan model
class OTTPlanAdmin(admin.ModelAdmin):
    list_display = ('get_platform', 'name', 'code', 'plan_group', 'validity_months',  'status', 'get_otts', 'price','flexible_plan_flag')  # Add price to the display
    list_filter = ('platform_id',  'status', 'flexible_plan_flag',  'validity_months', 'plan_group')  # Filter by platform_id and status
    search_fields = ('name', 'code', 'platform_id__name', 'validity_months')  # Search by platform's name, name, and code
    filter_horizontal = ('otts',)  # Allow multiple OTT selection in horizontal view

    # Display OTT names associated with the plan
    def get_otts(self, obj):
        return ", ".join([ott.name for ott in obj.otts.all()])  # Assuming 'name' is a field in the OTT model
    get_otts.short_description = 'OTTs'

    # Display the platform's name (from OTTAggregator)
    def get_platform(self, obj):
        return obj.platform_id.name  # Use platform_id to reference OTTAggregator
    get_platform.admin_order_field = 'platform_id__name'  # Sorting by platform's name
    get_platform.short_description = 'Platform'  # Label for the admin list view

    # Add price field to the list display
    def price(self, obj):
        return obj.price  # Ensure price is a field in your model
    price.short_description = 'Price'  # Label for the price column in the admin view

    # Filter active platforms in the form
    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == "platform_id":  # Correct foreign key field name
            kwargs["queryset"] = OTTAggregator.objects.filter(status='active')
        return super().formfield_for_foreignkey(db_field, request, **kwargs)

admin.site.register(OTTPlan, OTTPlanAdmin)



class SkylinkPlanAdmin(admin.ModelAdmin):
    list_display = ('name', 'code', 'amount', 'status', 'bandwidth_verified_flag', 'bandwidth', 'jiohotstar_flag','server_type')
    list_filter = ('server_type','status', 'bandwidth_verified_flag', 'bandwidth', 'jiohotstar_flag')
    filter_horizontal = ('ott_plans',)
    search_fields = ('name', 'code', 'bandwidth', 'amount')
    change_list_template = "ott_subscription/admin/skylinkplan_change_list.html"  # Your change list template

    def get_urls(self):
        urls = super().get_urls()
        custom_urls = [
            path('graph-view/', self.admin_site.admin_view(self.graph_view), name='skylinkplan-graph'),
        ]
        return custom_urls + urls

    def graph_view(self, request):
        all_plans = SkylinkPlan.objects.all().order_by('bandwidth', 'name')

        roadmap = defaultdict(lambda: defaultdict(list))

        for plan in all_plans:
            # Determine bandwidth group
            if plan.bandwidth_verified_flag:
                raw_bw = plan.bandwidth or 'Unknown'
                bandwidth = raw_bw.strip().title()
            else:
                bandwidth = 'Other Plans'

            # Extract price prefix from the name using regex
            match = re.match(r'(\d+)', plan.name.strip())
            price_prefix = match.group(1) if match else 'Others'

            # Append to the nested group
            roadmap[bandwidth][price_prefix].append({
                'name': plan.name,
                'amount': float(plan.amount),
                'jiohotstar_flag': plan.jiohotstar_flag,
            })

        # Sort roadmap keys: bandwidth numerically, price group numerically
        def bandwidth_sort_key(bw):
            if bw == 'Other Plans':
                return float('inf')
            m = re.search(r'(\d+)', bw)
            return int(m.group(1)) if m else float('inf')

        def price_sort_key(p):
            try:
                return int(p)
            except ValueError:
                return float('inf')  # Place 'Others' at the end

        sorted_roadmap = dict(sorted(roadmap.items(), key=lambda x: bandwidth_sort_key(x[0])))
        for bw in sorted_roadmap:
            sorted_roadmap[bw] = dict(sorted(sorted_roadmap[bw].items(), key=lambda x: price_sort_key(x[0])))

        context = {
            'roadmap': sorted_roadmap,
            'title': 'SkylinkPlan Roadmap View (Grouped by Price Prefix)',
        }
        return TemplateResponse(request, "ott_subscription/admin/skylinkplan_graph.html", context)


admin.site.register(SkylinkPlan, SkylinkPlanAdmin)
class OTTActivationLogAdmin(admin.ModelAdmin):
    list_display = (
        'client_id', 
        'phone_number',
        'platform_id', 
        'plan_id', 
        'activation_date_ist', 
        'billing_from_date_list',
        'billing_end_date_list',
        'status', 
        'message', 
        'subscription_tiers_display',
        'payment_gateway',
        'amount_display'
    )
    
    list_filter = ('status', 'platform_id', 'subscription_tiers', 'payment_gateway')
    search_fields = ('client_id', 'platform_id__name', 'plan_id','phone_number',)
    ordering = ('-activation_date',)
    date_hierarchy = 'activation_date'

    def activation_date_ist(self, obj):
        ist = pytz.timezone('Asia/Kolkata')
        return obj.activation_date.astimezone(ist).strftime('%Y-%m-%d %H:%M:%S')
    activation_date_ist.short_description = 'Activation Date (IST)'

    def billing_from_date_list(self, obj):
        if obj.billing_from_date:
            ist = pytz.timezone('Asia/Kolkata')
            dt = datetime.combine(obj.billing_from_date, time.min)
            return dt.astimezone(ist).strftime('%Y-%m-%d')
        return "-"
    billing_from_date_list.short_description = 'Billing From Date (IST)'

    def billing_end_date_list(self, obj):
        if obj.billing_to_date:
            ist = pytz.timezone('Asia/Kolkata')
            dt = datetime.combine(obj.billing_to_date, time.min)
            return dt.astimezone(ist).strftime('%Y-%m-%d')            
        return "-"
    billing_end_date_list.short_description = 'Billing To Date (IST)'

    def subscription_tiers_display(self, obj):
        return obj.subscription_tiers.capitalize()
    subscription_tiers_display.short_description = 'Subscription Tier'

    def amount_display(self, obj):
        if obj.subscription_tiers == 'paid':
            return f"{obj.payment_amount} {obj.payment_currency}"
        return '-'
    amount_display.short_description = 'Amount (Currency)'

    def formatted_input(self, obj):
        try:
            input_data = json.loads(obj.input)
            return format_html('<pre>{}</pre>', json.dumps(input_data, indent=2))
        except (ValueError, TypeError):
            return 'Invalid JSON or Empty'
    formatted_input.short_description = 'Formatted Input'

    def formatted_output(self, obj):
        try:
            output_data = json.loads(obj.output)
            return format_html('<pre>{}</pre>', json.dumps(output_data, indent=2))
        except (ValueError, TypeError):
            return 'Invalid JSON or Empty'
    formatted_output.short_description = 'Formatted Output'

    exclude = ('input', 'output',)
    readonly_fields = ('formatted_input', 'formatted_output', 'subscription_tiers_display', 'amount_display')

    def get_readonly_fields(self, request, obj=None):
        readonly_fields = super().get_readonly_fields(request, obj)
        if obj and obj.subscription_tiers == 'paid':
            readonly_fields += (
                'razorpay_order_id', 'razorpay_payment_id', 'razorpay_signature', 
                'payment_amount', 'payment_currency',
                'cashfree_order_id', 'cashfree_payment_id',
                'cashfree_payment_session_id', 'cashfree_raw_response'
            )
        return readonly_fields

admin.site.register(OTTActivationLog, OTTActivationLogAdmin)

@admin.register(JioHotstarCode)
class JioHotstarCodeAdmin(ImportExportModelAdmin):
    resource_class = JioHotstarCodeResource
    list_display = ('id', 'code', 'activated_flag', 'activated_date_ist', 'billing_cycle',  'expired_date_list', 'billing_from_date_list', 'billing_end_date_list', 'activated_client_id', 'client_phone_number', 'type')
    list_filter = ('activated_flag', 'activated_date', 'type', 'billing_cycle')
    search_fields = ('code', 'activated_client_id', 'client_phone_number')
    ordering = ('-activated_date',)
    date_hierarchy = 'activated_date'

    def activated_date_ist(self, obj):
        if obj.activated_date:
            ist = pytz.timezone('Asia/Kolkata')
            dt = obj.activated_date
            if is_naive(dt):
                dt = pytz.utc.localize(dt)
            return dt.astimezone(ist).strftime('%Y-%m-%d %H:%M:%S')
        return "-"
    activated_date_ist.short_description = 'Activated Date (IST)'
    
    # Convert expiration_date to IST
    def billing_from_date_list(self, obj):
        if obj.billing_from_date:
            ist = pytz.timezone('Asia/Kolkata')
            # Combine date with a time object to make it a datetime object
            dt = datetime.combine(obj.billing_from_date, time.min)
            return dt.astimezone(ist).strftime('%Y-%m-%d')
        return "-"
    billing_from_date_list.short_description = 'Billing From Date (IST)'
    

    def billing_end_date_list(self, obj):
        if obj.billing_to_date:
            ist = pytz.timezone('Asia/Kolkata')
            dt = datetime.combine(obj.billing_to_date, time.min)
            return dt.astimezone(ist).strftime('%Y-%m-%d')            
        return "-"
    billing_end_date_list.short_description = 'Billing To Date (IST)'

    def expired_date_list(self, obj):
        if obj.expired_date:
            ist = pytz.timezone('Asia/Kolkata')
            dt = datetime.combine(obj.expired_date, time.min)
            return dt.astimezone(ist).strftime('%Y-%m-%d')
        return "-"
    expired_date_list.short_description = 'Expired Date (IST)'


    # for the graph
     # Custom admin changelist template (optional if you want to insert a link/button)
    # Use custom change list template (optional)
    change_list_template = "ott_subscription/admin/jiohotstarcode_changelist.html"

    def get_urls(self):
        urls = super().get_urls()
        custom_urls = [
            path(
                'usage-graph/',
                self.admin_site.admin_view(self.usage_graph_view),
                name='ott_subscription_jiohotstarcode_graph',
            ),
        ]   
        return custom_urls + urls

        
        
    def usage_graph_view(self, request):
       
        def get_color_palette(n):
            h = random.random()
            s = 0.5 + random.random() / 2
            v = 0.95
            return [
                f'rgb({int(r*255)}, {int(g*255)}, {int(b*255)})'
                for r, g, b in [
                    colorsys.hsv_to_rgb((h + i / n) % 1.0, s, v)
                    for i in range(n)
                ]
            ]

        # Filters
        type_filter = request.GET.get('type')
        billing_cycle = request.GET.get('billing_cycle')
        start_date = request.GET.get('start_date')
        end_date = request.GET.get('end_date')

        queryset = self.model.objects.all()

        if type_filter:
            queryset = queryset.filter(type=type_filter)

        if billing_cycle:
            try:
                queryset = queryset.filter(billing_cycle=int(billing_cycle))
            except ValueError:
                pass

        try:
            parsed_start = datetime.strptime(start_date, "%Y-%m-%d").date() if start_date else None
        except ValueError:
            parsed_start = None

        try:
            parsed_end = datetime.strptime(end_date, "%Y-%m-%d").date() if end_date else None
        except ValueError:
            parsed_end = None

        if parsed_start:
            queryset = queryset.filter(activated_date__date__gte=parsed_start)
        if parsed_end:
            queryset = queryset.filter(activated_date__date__lte=parsed_end)

        df = pd.DataFrame.from_records(queryset.values('activated_date', 'type', 'billing_cycle'))
        if df.empty:
            df = pd.DataFrame(columns=['activated_date', 'type', 'billing_cycle'])

        df['activated_date'] = pd.to_datetime(df['activated_date'], errors='coerce')
        df['status'] = df['activated_date'].notnull().map({True: 'Activated', False: 'Unactivated'})
        df['date'] = df['activated_date'].dt.date
        df['type'] = df['type'].fillna('Unknown')
        df['billing_cycle'] = df['billing_cycle'].fillna('Unknown')

        context_graphs = {}

        if not df.empty:
            daily_summary = df[df['status'] == 'Activated'].groupby(['date', 'type']).size().reset_index(name='count')

            types = df['type'].unique().tolist()
            color_palette = get_color_palette(len(types))
            color_map = dict(zip(types, color_palette))

            # Line Chart
            fig_line = px.line(
                
                daily_summary, x='date', y='count', color='type', markers=True,
                title='Daily Activations by Type', hover_data=['count'],
                color_discrete_map=color_map
            )
            fig_line.update_layout(
                autosize=True,
                height=400,
                margin=dict(l=40, r=40, t=40, b=40),
                xaxis=dict(tickangle=45, tickfont=dict(size=10)),
                yaxis=dict(tickfont=dict(size=10))
            )
            fig_line.update_traces(marker=dict(size=6), line=dict(width=2))
            context_graphs['line_chart'] = pio.to_html(fig_line, full_html=False, include_plotlyjs='cdn',config={'displaylogo': False})

            # Bar Chart
            bar_data = df.groupby(['type', 'status']).size().unstack(fill_value=0).reset_index()
            fig_bar = go.Figure()
            for _, row in bar_data.iterrows():
                t = row['type']
                activated_count = row.get('Activated', 0)
                unactivated_count = row.get('Unactivated', 0)

                fig_bar.add_trace(go.Bar(
                    x=[t],
                    y=[activated_count],
                    name=f'{t} - Activated',
                    marker_color=color_map.get(t, None),
                    hovertemplate='Count: %{y}<extra></extra>'
                ))
                fig_bar.add_trace(go.Bar(
                    x=[t],
                    y=[unactivated_count],
                    name=f'{t} - Unactivated',
                    marker_color='grey',
                    hovertemplate='Count: %{y}<extra></extra>'
                ))

            fig_bar.update_layout(barmode='stack', title="Total Activations by Type", yaxis_title="Count", autosize=True, height=400,  margin=dict(l=40, r=10, t=40, b=40),
    xaxis=dict(tickfont=dict(size=10)),
    yaxis=dict(tickfont=dict(size=10)))
            context_graphs['bar_chart'] = pio.to_html(fig_bar, full_html=False, include_plotlyjs=False,   config={'displaylogo': False})

            # Pie Chart
            pie_data = df['status'].value_counts().reset_index()
            pie_data.columns = ['status', 'count']
            fig_pie = px.pie(pie_data, names='status', values='count', title="Activation Status Share")
            fig_pie.update_traces(hovertemplate='Status: %{label}<br>Count: %{value}<extra></extra>')
            fig_pie.update_layout(autosize=True, height=400)
            context_graphs['pie_chart'] = pio.to_html(fig_pie, full_html=False, include_plotlyjs=False,config={'displaylogo': False})

            # Area Chart
            area_data = df[df['status'] == 'Activated'].groupby(['date', 'type']).size().unstack(fill_value=0).cumsum().reset_index()
            fig_area = px.area(
                area_data, x='date', y=area_data.columns[1:],
                title="Cumulative Activations (Stacked Area)",
                color_discrete_sequence=color_palette
            )
            fig_area.update_layout(autosize=True, height=400)
            context_graphs['area_chart'] = pio.to_html(fig_area, full_html=False, include_plotlyjs=False, config={'displaylogo': False})

            # Heatmap
            heat_df = df[df['status'] == 'Activated'].dropna(subset=['billing_cycle'])
            if not heat_df.empty:
                top_cycles = heat_df['billing_cycle'].value_counts().nlargest(8).index
                heat_filtered = heat_df[heat_df['billing_cycle'].isin(top_cycles)]
                heatmap_data = heat_filtered.groupby(['date', 'billing_cycle']).size().unstack(fill_value=0)
                fig_heatmap = go.Figure(data=go.Heatmap(
                    z=heatmap_data.T.values,
                    x=heatmap_data.index.astype(str),
                    y=heatmap_data.columns.astype(str),
                    colorscale='YlGnBu',
                    hovertemplate='Date: %{x}<br>Billing Cycle: %{y}<br>Count: %{z}<extra></extra>'
                ))
                fig_heatmap.update_layout(
                    title="Heatmap: Billing Cycle vs Date",
                    xaxis_title="Date",
                    yaxis_title="Billing Cycle",
                    autosize=True,
                    height=400
                )
                context_graphs['heatmap'] = pio.to_html(fig_heatmap, full_html=False, include_plotlyjs=False, config={'displaylogo': False})

            valid_dates = df[df['status'] == 'Activated']['date'].dropna()
            start_summary = valid_dates.min() if not valid_dates.empty else None
            end_summary = valid_dates.max() if not valid_dates.empty else None

            summary_stats = {
                'total_activations': len(df[df['status'] == 'Activated']),
                'start_date': start_summary,
                'end_date': end_summary,
                'by_type': df[df['status'] == 'Activated']['type'].value_counts().to_dict()
            }
        else:
            summary_stats = {}

        type_options = self.model.objects.values_list('type', flat=True).distinct()
        billing_cycle_options = self.model.objects.values_list('billing_cycle', flat=True).distinct().order_by('billing_cycle')

        context = dict(
            self.admin_site.each_context(request),
            title="JioHotstar Activation Graphs",
            graphs=context_graphs,
            summary=summary_stats,
            selected_type=type_filter,
            selected_cycle=billing_cycle,
            selected_start=start_date,
            selected_end=end_date,
            type_options=type_options,
            billing_cycle_options=billing_cycle_options,
        )
        return TemplateResponse(request, "ott_subscription/admin/jiohotstarcode_graph.html", context)




@admin.register(IptvRequest)
class IptvRequestAdmin(admin.ModelAdmin):
    list_display = (
        'client_id',
        'phone_number',
        'email',
        'requested_at',
        'activation_code',
        'activated_by',
        'activated_at',
        'get_reason_not_activated',  # <-- use custom method
    )
    readonly_fields = ('client_id', 'phone_number', 'email')  # Make these read-only
    search_fields = ('client_id', 'phone_number', 'email')
    list_filter = ('requested_at',)
    ordering = ('-requested_at',)

    def get_reason_not_activated(self, obj):
        return obj.reason_not_activated
    get_reason_not_activated.short_description = 'Reason for not activated'


    


@admin.register(SupportVideo)
class SupportVideoAdmin(admin.ModelAdmin):
    list_display = ('title', 'order_id', 'is_active')
    list_editable = ('order_id',)  # Make order_id editable in list
    list_filter = ('is_active',)
    search_fields = ('title', 'subtitle')


@admin.register(TVChannel)
class TVChannelAdmin(admin.ModelAdmin):
    list_display = ('name', 'code', 'order_id', 'is_active')
    list_filter = ('is_active',)
    search_fields = ('name', 'code')
    ordering = ('order_id',)




@admin.register(CashfreePayment)
class CashfreePaymentAdmin(admin.ModelAdmin):
    list_display = (
        'client_id',
        'customer_email',
        'customer_phone',
        'platform_id',
        'plan_id',
        'order_id',
        'amount',
        'currency',
        'payment_status',
        'paid_at',
        'created_at',
    )
    list_filter = ('payment_status', 'platform_id', 'currency')
    search_fields = ('client_id', 'order_id', 'plan_id', 'platform_id__name',   'customer_email','customer_phone', )
    ordering = ('-created_at',)
    readonly_fields = ('created_at', 'paid_at', 'extra_data')  # fields that shouldn't be edited

    # Optional: nicely display extra_data JSON
    def formatted_extra_data(self, obj):
        import json
        try:
            return json.dumps(obj.extra_data, indent=2)
        except Exception:
            return obj.extra_data
    formatted_extra_data.short_description = "Extra Data"
    readonly_fields += ('formatted_extra_data',)

from django.contrib import admin
from django.test import RequestFactory
from django.contrib.sessions.middleware import SessionMiddleware
import json

from .models import ManualOTTActivation, OTTActivationLog
from ott_subscription.views import fetch_watcho_data, fetch_ottplay_data, fetch_playbox_data


@admin.register(ManualOTTActivation)
class ManualOTTActivationAdmin(admin.ModelAdmin):

    list_display = (
        "phone_number",
        "platform",
        "plan",
        "platform_2",
        "plan_2",
        "first_name",
        "last_name",
        "sky_id",
        "status",
        "created_at",
    )

    list_filter = ("platform", "status")

    search_fields = (
        "phone_number",
        "first_name",
        "last_name",
        "sky_id",
    )

    readonly_fields = ("created_at",)

    def save_model(self, request, obj, form, change):

        super().save_model(request, obj, form, change)

        # --------------------------------------------------
        # 🔴 BASIC VALIDATION
        # --------------------------------------------------
        if not obj.platform or not obj.plan or not obj.phone_number:
            obj.status = "Failed"
            obj.message = "First Platform, Plan and Phone number are required"
            obj.save()
            return

        if obj.platform_2 and not obj.plan_2:
            obj.status = "Failed"
            obj.message = "Second plan selected but Plan is missing"
            obj.save()
            return

        if obj.plan_2 and not obj.platform_2:
            obj.status = "Failed"
            obj.message = "Second platform missing"
            obj.save()
            return

        activation_results = []

        # --------------------------------------------------
        # 🔥 PLAN ACTIVATION FUNCTION
        # --------------------------------------------------
        def activate(platform, plan):

            payload = {
                "client_id": obj.phone_number,
                "platform_id": platform.id,
                "plan_id": plan.id,
                "manual_flag": 1,
                "first_name": obj.first_name,
                "last_name": obj.last_name,
                "email": getattr(obj, "email", ""),
                "address_city": obj.sky_id,
            }

            factory = RequestFactory()

            fake_request = factory.post(
                "/fake-url/",
                data=json.dumps(payload),
                content_type="application/json"
            )

            # Attach session
            middleware = SessionMiddleware(lambda req: None)
            middleware.process_request(fake_request)
            fake_request.session.save()

            try:
                if platform.code == "watcho":
                    response = fetch_watcho_data(fake_request)
                elif platform.code == "ottplay":
                    response = fetch_ottplay_data(fake_request)
                elif platform.code == "play_box":
                    response = fetch_playbox_data(fake_request)                    
                else:
                    return {
                        "status": "Failed",
                        "platform": platform.name,
                        "plan": plan.code,
                        "message": "Platform not supported"
                    }

                # Safe decode
                try:
                    response_data = json.loads(response.content.decode("utf-8"))
                except Exception:
                    response_data = {"message": "Invalid API response"}

                result_status = "Success" if response.status_code == 200 else "Failed"

                # Log activation
                OTTActivationLog.objects.create(
                    client_id=obj.phone_number,
                    platform_id=platform,
                    plan_id=plan.code,
                    status=result_status,
                    message=response_data.get("message"),
                    input=response_data.get("input"),
                    response_status=response_data.get("response_status"),
                    output=response_data.get("output"),
                    endpoint=response_data.get("endpoint"),
                    phone_number=obj.phone_number,
                )

                return {
                    "status": result_status,
                    "platform": platform.name,
                    "plan": plan.code,
                    "message": response_data.get("message")
                }

            except Exception as e:
                return {
                    "status": "Failed",
                    "platform": platform.name,
                    "plan": plan.code,
                    "message": str(e)
                }

        # --------------------------------------------------
        # 🚀 ACTIVATE FIRST & SECOND PLAN
        # --------------------------------------------------
        try:

            # Activate first plan
            activation_results.append(
                activate(obj.platform, obj.plan)
            )

            # Activate second plan if exists
            if obj.platform_2 and obj.plan_2:
                activation_results.append(
                    activate(obj.platform_2, obj.plan_2)
                )

            # --------------------------------------------------
            # 🧠 FINAL STATUS LOGIC WITH DETAILS
            # --------------------------------------------------
            success_results = [r for r in activation_results if r["status"] == "Success"]
            failed_results = [r for r in activation_results if r["status"] == "Failed"]

            if len(failed_results) == 0:
                obj.status = "Success"
                obj.message = "All plans activated successfully"

            elif len(success_results) == 0:
                obj.status = "Failed"

                failed_details = ", ".join(
                    f"{r['platform']} - {r['plan']} ({r['message']})"
                    for r in failed_results
                )

                obj.message = f"All failed: {failed_details}"

            else:
                obj.status = "Partial Success"

                failed_details = ", ".join(
                    f"{r['platform']} - {r['plan']} ({r['message']})"
                    for r in failed_results
                )

                obj.message = f"Failed: {failed_details}"

            obj.save()

        except Exception as e:
            obj.status = "Failed"
            obj.message = str(e)
            obj.save()
