import { createServerFn } from "@tanstack/react-start";
import { z } from "zod";
import { requireSupabaseAuth } from "@/integrations/supabase/auth-middleware";
import { dispatchSms } from "./sms-providers.server";

const BD_PHONE = /^01[3-9]\d{8}$/;

function normalizePhone(raw: string): string | null {
  const digits = raw.replace(/\D/g, "");
  if (digits.startsWith("880") && digits.length === 13) return "0" + digits.slice(3);
  if (digits.length === 11) return digits;
  if (digits.length === 10 && digits.startsWith("1")) return "0" + digits;
  return null;
}

/** Send a manual SMS — creates log row, dispatches to provider, updates log. */
export const sendSms = createServerFn({ method: "POST" })
  .middleware([requireSupabaseAuth])
  .inputValidator((input) =>
    z
      .object({
        customer_id: z.string().uuid().nullable().optional(),
        phone: z.string().min(10).max(20),
        message: z.string().min(1).max(1000),
        type: z.enum(["manual", "invoice", "payment", "due", "delivery"]).default("manual"),
        reference_id: z.string().max(64).optional(),
      })
      .parse(input),
  )
  .handler(async ({ data, context }) => {
    const { supabase, userId } = context;

    const phone = normalizePhone(data.phone);
    if (!phone || !BD_PHONE.test(phone)) {
      return { ok: false, error: "Invalid Bangladeshi phone number (must be 01XXXXXXXXX)" };
    }

    const { data: settings, error: sErr } = await supabase
      .from("sms_settings")
      .select("*")
      .limit(1)
      .maybeSingle();
    if (sErr || !settings) return { ok: false, error: "SMS settings not configured" };
    if (!settings.sms_enabled) return { ok: false, error: "SMS is disabled. Enable it in Settings." };
    if (!settings.api_token || !settings.sender_id) {
      return { ok: false, error: "API token / Sender ID missing in SMS settings" };
    }

    const { data: log, error: lErr } = await supabase
      .from("sms_logs")
      .insert({
        customer_id: data.customer_id ?? null,
        phone,
        message: data.message,
        type: data.type,
        reference_id: data.reference_id ?? "",
        status: "pending",
        provider: settings.provider,
        created_by: userId,
      })
      .select()
      .single();
    if (lErr || !log) return { ok: false, error: lErr?.message || "Failed to create SMS log" };

    try {
      const result = await dispatchSms({
        provider: settings.provider,
        baseUrl: settings.base_url,
        apiToken: settings.api_token,
        username: settings.api_secret,
        sid: settings.sender_id,
        phone,
        message: data.message,
        csms_id: log.id,
      });
      const sentOk = result.ok;
      await supabase
        .from("sms_logs")
        .update({
          status: sentOk ? "sent" : "failed",
          provider_response: (result.body ?? {}) as never,
          error_message: sentOk ? "" : result.errorMessage || `HTTP ${result.status}`,
          sent_at: sentOk ? new Date().toISOString() : null,
        })
        .eq("id", log.id);
      return sentOk
        ? { ok: true, id: log.id }
        : { ok: false, id: log.id, error: result.errorMessage || `HTTP ${result.status}` };
    } catch (e) {
      const msg = e instanceof Error ? e.message : String(e);
      await supabase
        .from("sms_logs")
        .update({ status: "failed", error_message: msg })
        .eq("id", log.id);
      return { ok: false, id: log.id, error: msg };
    }
  });

/** Flush all pending SMS rows (used to send auto-generated invoice SMS). */
export const flushPendingSms = createServerFn({ method: "POST" })
  .middleware([requireSupabaseAuth])
  .handler(async ({ context }) => {
    const { supabase } = context;
    const { data: settings } = await supabase
      .from("sms_settings")
      .select("*")
      .limit(1)
      .maybeSingle();
    if (!settings || !settings.sms_enabled || !settings.api_token || !settings.sender_id) {
      return { processed: 0, sent: 0, failed: 0, skipped: true };
    }

    const { data: pending } = await supabase
      .from("sms_logs")
      .select("*")
      .eq("status", "pending")
      .order("created_at", { ascending: true })
      .limit(50);

    let sent = 0;
    let failed = 0;
    for (const row of pending ?? []) {
      const phone = normalizePhone(row.phone);
      if (!phone || !BD_PHONE.test(phone)) {
        await supabase
          .from("sms_logs")
          .update({ status: "failed", error_message: "Invalid phone format" })
          .eq("id", row.id);
        failed++;
        continue;
      }
      try {
        const result = await dispatchSms({
          provider: settings.provider,
          baseUrl: settings.base_url,
          apiToken: settings.api_token,
          username: settings.api_secret,
          sid: settings.sender_id,
          phone,
          message: row.message,
          csms_id: row.id,
        });
        const ok = result.ok;
        await supabase
          .from("sms_logs")
          .update({
            status: ok ? "sent" : "failed",
            provider_response: (result.body ?? {}) as never,
            error_message: ok ? "" : result.errorMessage || `HTTP ${result.status}`,
            sent_at: ok ? new Date().toISOString() : null,
          })
          .eq("id", row.id);
        ok ? sent++ : failed++;
      } catch (e) {
        const msg = e instanceof Error ? e.message : String(e);
        await supabase
          .from("sms_logs")
          .update({ status: "failed", error_message: msg })
          .eq("id", row.id);
        failed++;
      }
    }
    return { processed: pending?.length ?? 0, sent, failed, skipped: false };
  });

/** Queue a group SMS for a list of customer ids. */
export const sendGroupSms = createServerFn({ method: "POST" })
  .middleware([requireSupabaseAuth])
  .inputValidator((input) =>
    z
      .object({
        customer_ids: z.array(z.string().uuid()).min(1).max(2000),
        message: z.string().min(1).max(1000),
      })
      .parse(input),
  )
  .handler(async ({ data, context }) => {
    const { supabase, userId } = context;
    const { data: settings } = await supabase
      .from("sms_settings")
      .select("provider, sms_enabled")
      .limit(1)
      .maybeSingle();
    if (!settings || !settings.sms_enabled) {
      return { ok: false, error: "SMS is disabled in settings", queued: 0 };
    }

    const { data: customers } = await supabase
      .from("customers")
      .select("id, name, mobile, total_due")
      .in("id", data.customer_ids)
      .is("deleted_at", null);

    let queued = 0;
    let skipped = 0;
    const rows: Array<{customer_id:string;phone:string;message:string;type:string;status:string;provider:string;created_by:string|null}> = [];
    for (const c of customers ?? []) {
      const phone = (c.mobile || "").replace(/\D/g, "");
      if (!phone) {
        skipped++;
        continue;
      }
      let msg = data.message;
      msg = msg.replace(/\{name\}/g, c.name || "Customer");
      msg = msg.replace(/\{due\}/g, String(c.total_due ?? 0));
      rows.push({
        customer_id: c.id,
        phone: c.mobile,
        message: msg,
        type: "manual",
        status: "pending",
        provider: settings.provider,
        created_by: userId,
      });
      queued++;
    }
    if (rows.length > 0) {
      const { error } = await supabase.from("sms_logs").insert(rows);
      if (error) return { ok: false, error: error.message, queued: 0 };
    }
    return { ok: true, queued, skipped };
  });

/** Queue due-reminder SMS for all customers with outstanding due. */
export const queueDueReminders = createServerFn({ method: "POST" })
  .middleware([requireSupabaseAuth])
  .handler(async ({ context }) => {
    const { supabase, userId } = context;
    const { data: settings } = await supabase
      .from("sms_settings")
      .select("*")
      .limit(1)
      .maybeSingle();
    if (!settings || !settings.sms_enabled) {
      return { ok: false, error: "SMS is disabled", queued: 0 };
    }
    const minDue = Number(settings.due_min_amount ?? 1);
    const { data: customers } = await supabase
      .from("customers")
      .select("id, name, mobile, total_due")
      .gt("total_due", minDue - 0.0001)
      .is("deleted_at", null)
      .limit(2000);

    let queued = 0;
    const rows: Array<{customer_id:string;phone:string;message:string;type:string;status:string;provider:string;created_by:string|null}> = [];
    for (const c of customers ?? []) {
      if (!c.mobile) continue;
      let msg = settings.due_template || "Your due is {due}";
      msg = msg.replace(/\{name\}/g, c.name || "Customer");
      msg = msg.replace(/\{due\}/g, String(c.total_due ?? 0));
      msg = msg.replace(/\{amount\}/g, String(c.total_due ?? 0));
      rows.push({
        customer_id: c.id,
        phone: c.mobile,
        message: msg,
        type: "due",
        status: "pending",
        provider: settings.provider,
        created_by: userId,
      });
      queued++;
    }
    if (rows.length > 0) {
      const { error } = await supabase.from("sms_logs").insert(rows);
      if (error) return { ok: false, error: error.message, queued: 0 };
    }
    return { ok: true, queued };
  });

