import { CampaignRepository } from "@/internal/repository/campaigns/campaigns";
import { BlockedEmailRepository } from "@/internal/repository/campaigns/blocked_emails";
import { DefaultEmailRepository } from "@/internal/repository/campaigns/default_emails";
import { ExternalMemberRepository } from "@/internal/repository/members/external_members";
import { logError } from "@/lib/logger";
import { invalidateCacheByPrefix } from "@/lib/redis.utils";
import { error, success } from "@/lib/response";
import { CampaignService } from "@/v1/services/admin/notifications/campaign.service";
import type { Context } from "hono";

const CAMPAIGN_CACHE_PREFIX = "GET:/v1/admin-console/notifications/campaigns";

export const createCampaignHandler = async (c: Context) => {
  try {
    const body = await c.req.json();
    if (!body.name) body.name = `Campaign_${Date.now()}`;
    const adminEmail = c.get("adminEmail") as string | undefined;
    if (adminEmail) {
      body.published_by = adminEmail;
    }
    const db = c.get("datastore");
    const memberDb = c.get("memberDatastore");
    const redis = c.get("redisDB");

    const service = new CampaignService(
      new CampaignRepository(db),
      new ExternalMemberRepository(memberDb),
      new BlockedEmailRepository(db),
      new DefaultEmailRepository(db),
    );

    const campaign = await service.createCampaign(body);
    if (campaign) {
      c.set("entityId", campaign.id);
    }

    // Invalidate cache
    if (redis) {
      await invalidateCacheByPrefix(redis, CAMPAIGN_CACHE_PREFIX);
    }

    return success(c, campaign, "Campaign created successfully");
  } catch (e: any) {
    return error(c, e.message || "Failed to create campaign", 500);
  }
};

export const updateCampaignHandler = async (c: Context) => {
  try {
    const id = c.req.param("id") as string;
    const body = await c.req.json();
    // Allow updating name if provided
    const db = c.get("datastore");
    const memberDb = c.get("memberDatastore");
    const redis = c.get("redisDB");

    const service = new CampaignService(
      new CampaignRepository(db),
      new ExternalMemberRepository(memberDb),
      new BlockedEmailRepository(db),
      new DefaultEmailRepository(db),
    );

    const campaign = await service.updateCampaign(id, body);
    if (campaign) {
      c.set("entityId", campaign.id);
    }

    // Invalidate cache
    if (redis) {
      await invalidateCacheByPrefix(redis, CAMPAIGN_CACHE_PREFIX);
    }

    return success(c, campaign, "Campaign updated successfully");
  } catch (e: any) {
    return error(c, e.message || "Failed to update campaign", 500);
  }
};

export const sendCampaignHandler = async (c: Context) => {
  const id = c.req.param("id") as string;
  try {
    const db = c.get("datastore");
    const memberDb = c.get("memberDatastore");
    const redis = c.get("redisDB");

    const service = new CampaignService(
      new CampaignRepository(db),
      new ExternalMemberRepository(memberDb),
      new BlockedEmailRepository(db),
      new DefaultEmailRepository(db),
    );
    c.set("entityId", id);

    // Start sending in background (via RabbitMQ)
    service.enqueueCampaign(id).catch((e) => {
      logError(`Background campaign execution failed for ${id}: ${e}`);
    });

    // Invalidate cache since status will change to SENDING/QUEUED
    if (redis) {
      await invalidateCacheByPrefix(redis, CAMPAIGN_CACHE_PREFIX);
    }

    return success(
      c,
      { success: true },
      "Campaign sending initiated in background",
      202,
    );
  } catch (e: any) {
    return error(c, e.message || "Failed to initiate campaign sending", 500);
  }
};

export const sendTestCampaignHandler = async (c: Context) => {
  try {
    const body = await c.req.json();
    const db = c.get("datastore");
    const memberDb = c.get("memberDatastore");

    const service = new CampaignService(
      new CampaignRepository(db),
      new ExternalMemberRepository(memberDb),
      new BlockedEmailRepository(db),
      new DefaultEmailRepository(db),
    );

    if (!body.target_email) {
      return error(c, "target_email is required", 400);
    }

    if (!body.name)
      body.name = "test_adding";

    await service.sendTestCampaign(body);
    return success(c, { success: true }, "Test campaign sent successfully");
  } catch (e: any) {
    return error(c, e.message || "Failed to send test campaign", 500);
  }
};

export const listCampaignsHandler = async (c: Context) => {
  try {
    const query = c.req.query();
    const start = Number.parseInt(query.start || "0", 10);
    const limit = Number.parseInt(query.limit || "50", 10);

    const fromDate = query.fromDate || query.fromdate;
    const toDate = query.toDate || query.todate;

    const filters = {
      status: query.status,
      search: query.search,
      country: query.country,
      city: query.city,
      platform: query.platform,
      fromDate: fromDate,
      toDate: toDate,
      sortBy: query.sortBy,
      sortOrder: (query.sortOrder as 'asc' | 'desc') || undefined,
    };

    const db = c.get("datastore");
    const memberDb = c.get("memberDatastore");

    const service = new CampaignService(
      new CampaignRepository(db),
      new ExternalMemberRepository(memberDb),
      new BlockedEmailRepository(db),
      new DefaultEmailRepository(db),
    );
    const campaigns = await service.list(limit, start, filters);

    return success(c, campaigns, "Campaigns retrieved successfully");
  } catch (e: any) {
    return error(c, e.message || "Failed to list campaigns", 500);
  }
};

export const campaignsAnalyticsHandler = async (c: Context) => {
  try {
    const query = c.req.query();
    const range = query.range as "7d" | "30d" | "90d" | undefined;
    const fromDate = query.fromDate || query.fromdate;
    const toDate = query.toDate || query.todate;

    const db = c.get("datastore");
    const memberDb = c.get("memberDatastore");

    const service = new CampaignService(
      new CampaignRepository(db),
      new ExternalMemberRepository(memberDb),
      new BlockedEmailRepository(db),
      new DefaultEmailRepository(db),
    );
    const analytics = await service.getAnalytics({ range, fromDate, toDate });

    return success(c, analytics, "Campaign analytics retrieved successfully");
  } catch (e: any) {
    return error(c, e.message || "Failed to get campaign analytics", 500);
  }
};

export const getCampaignHandler = async (c: Context) => {
  try {
    const id = c.req.param("id") as string;
    const db = c.get("datastore");
    const memberDb = c.get("memberDatastore");

    const service = new CampaignService(
      new CampaignRepository(db),
      new ExternalMemberRepository(memberDb),
      new BlockedEmailRepository(db),
      new DefaultEmailRepository(db),
    );
    const campaign = await service.getCampaign(id);

    return success(c, campaign, "Campaign retrieved successfully");
  } catch (e: any) {
    return error(c, e.message || "Failed to get campaign", 500);
  }
};

export const getTargetMetadataHandler = async (c: Context) => {
  try {
    const query = c.req.query();
    const country = query.country;

    const db = c.get("datastore");
    const memberDb = c.get("memberDatastore");

    const service = new CampaignService(
      new CampaignRepository(db),
      new ExternalMemberRepository(memberDb),
      new BlockedEmailRepository(db),
      new DefaultEmailRepository(db),
    );
    const metadata = await service.getTargetMetadata({ country });

    return success(c, metadata, "Metadata retrieved successfully");
  } catch (e: any) {
    return error(c, e.message || "Failed to retrieve metadata", 500);
  }
};

export const getAudienceCountHandler = async (c: Context) => {
  try {
    const body = await c.req.json();
    const db = c.get("datastore");
    const memberDb = c.get("memberDatastore");

    const service = new CampaignService(
      new CampaignRepository(db),
      new ExternalMemberRepository(memberDb),
      new BlockedEmailRepository(db),
      new DefaultEmailRepository(db),
    );
    const count = await service.getAudienceCount(body);
    return success(c, { count }, "Audience count retrieved successfully");
  } catch (e: any) {
    return error(c, e.message || "Failed to count audience", 500);
  }
};

export const getAudienceMembersHandler = async (c: Context) => {
  try {
    const body = await c.req.json();
    const db = c.get("datastore");
    const memberDb = c.get("memberDatastore");

    const service = new CampaignService(
      new CampaignRepository(db),
      new ExternalMemberRepository(memberDb),
      new BlockedEmailRepository(db),
      new DefaultEmailRepository(db),
    );
    const result = await service.getAudienceMembers({
      criteria: body.criteria,
      limit: body.limit,
      offset: body.offset,
      search: body.search
    });
    return success(c, result, "Audience members retrieved successfully");
  } catch (e: any) {
    return error(c, e.message || "Failed to list audience members", 500);
  }
};

export const deleteCampaignHandler = async (c: Context) => {
  try {
    const id = c.req.param("id") as string;
    const db = c.get("datastore");
    const memberDb = c.get("memberDatastore");
    const redis = c.get("redisDB");

    const service = new CampaignService(
      new CampaignRepository(db),
      new ExternalMemberRepository(memberDb),
      new BlockedEmailRepository(db),
      new DefaultEmailRepository(db),
    );
    const result = await service.deleteCampaign(id);
    c.set("entityId", id);
    if (!result) {
      return error(c, "Campaign not found or already deleted", 404);
    }

    // Invalidate cache
    if (redis) {
      await invalidateCacheByPrefix(redis, CAMPAIGN_CACHE_PREFIX);
    }

    return success(c, { success: true }, "Campaign deleted successfully");
  } catch (e: any) {
    return error(c, e.message || "Failed to delete campaign", 500);
  }
};

export const activateCampaignHandler = async (c: Context) => {
  try {
    const id = c.req.param("id") as string;
    const db = c.get("datastore");
    const memberDb = c.get("memberDatastore");
    const redis = c.get("redisDB");

    const service = new CampaignService(
      new CampaignRepository(db),
      new ExternalMemberRepository(memberDb),
      new BlockedEmailRepository(db),
      new DefaultEmailRepository(db),
    );
    const result = await service.activateCampaign(id);
    c.set("entityId", id);
    if (!result) {
      return error(c, "Campaign not found", 404);
    }

    if (redis) {
      await invalidateCacheByPrefix(redis, CAMPAIGN_CACHE_PREFIX);
    }

    return success(c, { success: true }, "Campaign activated successfully");
  } catch (e: any) {
    return error(c, e.message || "Failed to activate campaign", 500);
  }
};
export const stopCampaignHandler = async (c: Context) => {
  try {
    const id = c.req.param("id") as string;
    const db = c.get("datastore");
    const memberDb = c.get("memberDatastore");
    const redis = c.get("redisDB");

    const service = new CampaignService(
      new CampaignRepository(db),
      new ExternalMemberRepository(memberDb),
      new BlockedEmailRepository(db),
      new DefaultEmailRepository(db),
    );

    await service.stopCampaign(id);
    c.set("entityId", id);

    if (redis) {
      await invalidateCacheByPrefix(redis, CAMPAIGN_CACHE_PREFIX);
    }

    return success(c, { success: true }, "Campaign stopped successfully");
  } catch (e: any) {
    return error(c, e.message || "Failed to stop campaign", 500);
  }
};

export const resumeCampaignHandler = async (c: Context) => {
  try {
    const id = c.req.param("id") as string;
    const db = c.get("datastore");
    const memberDb = c.get("memberDatastore");
    const redis = c.get("redisDB");

    const service = new CampaignService(
      new CampaignRepository(db),
      new ExternalMemberRepository(memberDb),
      new BlockedEmailRepository(db),
      new DefaultEmailRepository(db),
    );

    await service.resumeCampaign(id);
    c.set("entityId", id);

    if (redis) {
      await invalidateCacheByPrefix(redis, CAMPAIGN_CACHE_PREFIX);
    }

    return success(
      c,
      { success: true },
      "Campaign resumed successfully",
      202,
    );
  } catch (e: any) {
    return error(c, e.message || "Failed to resume campaign", 500);
  }
};

export const getCampaignRecipientsHandler = async (c: Context) => {
  try {
    const id = c.req.param("id") as string;
    const query = c.req.query();
    const limit = Number.parseInt(query.limit || "50", 10);
    const offset = Number.parseInt(query.start || "0", 10);
    const search = query.search || undefined;
    const status = query.status || undefined;
    const seenStatus = c.req.query("seen_status") || undefined;

    const db = c.get("datastore");
    const memberDb = c.get("memberDatastore");

    const service = new CampaignService(
      new CampaignRepository(db),
      new ExternalMemberRepository(memberDb),
      new BlockedEmailRepository(db),
      new DefaultEmailRepository(db),
    );

    const result = await service.getCampaignRecipients(id, limit, offset, search, status, seenStatus);
    return success(c, result, "Recipients retrieved successfully");
  } catch (e: any) {
    return error(c, e.message || "Failed to get recipients", 500);
  }
};

export const listBlockedEmailsHandler = async (c: Context) => {
  try {
    const query = c.req.query();
    const limit = Number.parseInt(query.limit || "50", 10);
    const start = Number.parseInt(query.start || "0", 10);
    const search = query.search || undefined;

    const db = c.get("datastore");
    const repo = new BlockedEmailRepository(db);
    const result = await repo.list(limit, start, search);

    return success(c, result, "Blocked emails retrieved successfully");
  } catch (e: any) {
    console.error("List blocked emails error:", e);
    return error(c, e.message || "Failed to list blocked emails", 500);
  }
};

export const createBlockedEmailHandler = async (c: Context) => {
  try {
    const { email } = await c.req.json();
    if (!email) return error(c, "Email is required", 400);

    const db = c.get("datastore");
    const adminEmail = c.get("adminEmail") as string | undefined;
    const repo = new BlockedEmailRepository(db);
    const result = await repo.create(email, adminEmail);

    return success(c, result, "Email added to block list successfully");
  } catch (e: any) {
    console.error("Create blocked email error:", e);
    return error(c, e.message || "Failed to add email to block list", 500);
  }
};

export const deleteBlockedEmailHandler = async (c: Context) => {
  try {
    const id = c.req.param("id");
    if (!id) return error(c, "ID is required", 400);

    const db = c.get("datastore");
    const repo = new BlockedEmailRepository(db);
    await repo.delete(id);

    return success(c, { success: true }, "Email removed from block list successfully");
  } catch (e: any) {
    console.error("Delete blocked email error:", e);
    return error(c, e.message || "Failed to remove email from block list", 500);
  }
};

export const toggleBlockedEmailHandler = async (c: Context) => {
  try {
    const id = c.req.param("id");
    if (!id) return error(c, "ID is required", 400);
    const { is_active } = await c.req.json();
    if (typeof is_active !== "boolean") return error(c, "is_active is required", 400);

    const db = c.get("datastore");
    const adminEmail = c.get("adminEmail") as string | undefined;
    const repo = new BlockedEmailRepository(db);
    const result = await repo.toggleActive(id, is_active, adminEmail);

    return success(c, result, "Blocked email status updated successfully");
  } catch (e: any) {
    console.error("Toggle blocked email error:", e);
    return error(c, e.message || "Failed to toggle blocked email status", 500);
  }
};

// Default Email Handlers

export const listDefaultEmailsHandler = async (c: Context) => {
  try {
    const db = c.get("datastore");
    const repo = new DefaultEmailRepository(db);
    const result = await repo.list();

    return success(c, result, "Default emails retrieved successfully");
  } catch (e: any) {
    console.error("List default emails error:", e);
    return error(c, e.message || "Failed to list default emails", 500);
  }
};

export const addDefaultEmailHandler = async (c: Context) => {
  try {
    const { email } = await c.req.json();
    if (!email) return error(c, "Email is required", 400);

    const db = c.get("datastore");
    const adminEmail = c.get("adminEmail") as string | undefined;
    const repo = new DefaultEmailRepository(db);
    const result = await repo.add(email, adminEmail);

    if (!result) {
      return error(c, "Email already exists in default list", 409);
    }

    return success(c, result, "Default email added successfully");
  } catch (e: any) {
    console.error("Add default email error:", e);
    return error(c, e.message || "Failed to add default email", 500);
  }
};

export const deleteDefaultEmailHandler = async (c: Context) => {
  try {
    const id = c.req.param("id");
    if (!id) return error(c, "ID is required", 400);

    const db = c.get("datastore");
    const repo = new DefaultEmailRepository(db);
    await repo.delete(id);

    return success(c, { success: true }, "Default email removed successfully");
  } catch (e: any) {
    console.error("Delete default email error:", e);
    return error(c, e.message || "Failed to remove default email", 500);
  }
};

