import { createClient } from "https://esm.sh/@supabase/supabase-js@2.99.1";

const corsHeaders = {
  "Access-Control-Allow-Origin": "*",
  "Access-Control-Allow-Headers": "authorization, x-client-info, apikey, content-type",
};

function jsonResponse(body: unknown, status = 200) {
  return new Response(JSON.stringify(body), {
    status,
    headers: { ...corsHeaders, "Content-Type": "application/json" },
  });
}

function normalize(value: unknown) {
  return String(value ?? "").trim();
}

function normalizeEmail(value: unknown) {
  return normalize(value).toLowerCase();
}

function isUuid(value: string) {
  return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);
}

function escapeHtml(value: string) {
  return String(value)
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/\"/g, "&quot;")
    .replace(/'/g, "&#39;");
}

function buildActionEmailHtml({ title, intro, buttonLabel, actionLink }: { title: string; intro: string; buttonLabel: string; actionLink: string }) {
  return `
    <div style="font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Arial,sans-serif;max-width:600px;margin:0 auto;">
      <h2 style="color:#1e293b;margin-bottom:16px;">${escapeHtml(title)}</h2>
      <p style="color:#334155;font-size:15px;line-height:1.6;">${escapeHtml(intro)}</p>
      <div style="text-align:center;margin:28px 0;">
        <a href="${escapeHtml(actionLink)}" style="background-color:#0f172a;color:#ffffff;padding:12px 28px;text-decoration:none;border-radius:6px;font-weight:600;display:inline-block;font-size:15px;">${escapeHtml(buttonLabel)}</a>
      </div>
      <p style="color:#64748b;font-size:13px;">If you did not expect this email, you can safely ignore it.</p>
    </div>
  `;
}

async function getAuthorizedCaller(req: Request, anonKey: string) {
  const authHeader = req.headers.get("authorization") || "";
  if (!authHeader.startsWith("Bearer ")) return { error: jsonResponse({ error: "Unauthorized" }, 401) };

  const callerClient = createClient(Deno.env.get("SUPABASE_URL")!, anonKey, {
    global: { headers: { Authorization: authHeader } },
  });
  const token = authHeader.replace("Bearer ", "");
  const { data: claimsData, error: claimsError } = await callerClient.auth.getClaims(token);
  const callerId = claimsData?.claims?.sub;
  if (claimsError || !callerId) return { error: jsonResponse({ error: "Unauthorized" }, 401) };

  const [{ data: isAdmin }, { data: isManager }] = await Promise.all([
    callerClient.rpc("has_role", { _user_id: callerId, _role: "admin" }),
    callerClient.rpc("has_role", { _user_id: callerId, _role: "manager" }),
  ]);
  if (!isAdmin && !isManager) return { error: jsonResponse({ error: "Insufficient permissions" }, 403) };

  return { callerClient, callerId, authHeader };
}

async function getVerifiedSender(adminClient: any) {
  const { data, error } = await adminClient
    .from("email_senders")
    .select("id")
    .eq("is_active", true)
    .eq("verified", true)
    .order("is_default", { ascending: false })
    .order("updated_at", { ascending: false })
    .limit(1);
  if (error) return null;
  return data?.[0] ?? null;
}

async function sendManagedEmail(callerClient: any, recipient: string, subject: string, html: string) {
  const adminClient = createClient(Deno.env.get("SUPABASE_URL")!, Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!);
  const sender = await getVerifiedSender(adminClient);
  if (!sender?.id) return { skipped: true, reason: "No verified email sender is configured" };

  const { data, error } = await callerClient.functions.invoke("send-smtp-email", {
    body: { sender_id: sender.id, recipient: [recipient], subject, body: html, html, debug: false },
  });
  if (error) throw error;
  if (data?.success === false) throw new Error(data.error || "Email send failed");
  return { skipped: false };
}

async function findMatchingOwner(adminClient: any, lastName: string, email: string, unitIdentifier: string, accountNumber: string) {
  const unitFilters = [];
  if (unitIdentifier) {
    unitFilters.push(`unit_number.ilike.${unitIdentifier}`);
    if (isUuid(unitIdentifier)) unitFilters.push(`id.eq.${unitIdentifier}`);
  }
  if (accountNumber) unitFilters.push(`account_number.ilike.${accountNumber}`);
  if (!unitFilters.length) return { unit: null, owner: null };

  const { data: units, error: unitErr } = await adminClient
    .from("units")
    .select("id, association_id, unit_number, account_number")
    .or(unitFilters.join(","));
  if (unitErr) throw unitErr;
  if (!units?.length) return { unit: null, owner: null };

  const unitIds = units.map((u: any) => u.id);
  const { data: owners, error: ownerErr } = await adminClient
    .from("owners")
    .select("id, first_name, last_name, email, association_id, unit_id, user_id, exclude_from_signin")
    .in("unit_id", unitIds)
    .eq("status", "active")
    .ilike("last_name", lastName);
  if (ownerErr) throw ownerErr;

  const owner = (owners || []).find((o: any) => !email || normalizeEmail(o.email) === email) || owners?.[0] || null;
  const unit = owner ? units.find((u: any) => u.id === owner.unit_id) : units[0];
  return { unit, owner };
}

async function createOrLinkOwnerAccount(adminClient: any, owner: any, email: string) {
  const fullName = `${owner.first_name || ""} ${owner.last_name || ""}`.trim();
  let userId = owner.user_id;

  if (!userId) {
    const tempPassword = `Temp-${crypto.randomUUID()}!`;
    const { data: authData, error: createErr } = await adminClient.auth.admin.createUser({
      email,
      password: tempPassword,
      email_confirm: true,
      user_metadata: { full_name: fullName },
    });

    if (createErr && createErr.message?.includes("already been registered")) {
      const { data: users } = await adminClient.auth.admin.listUsers();
      userId = users.users.find((u: any) => normalizeEmail(u.email) === email)?.id;
    } else if (createErr) {
      throw createErr;
    } else {
      userId = authData.user?.id;
    }
  }

  if (!userId) throw new Error("Could not create or find user account");

  await adminClient.from("owners").update({ user_id: userId, email }).eq("id", owner.id);

  const { data: existingProfile } = await adminClient.from("profiles").select("user_id").eq("user_id", userId).maybeSingle();
  if (!existingProfile) await adminClient.from("profiles").insert({ user_id: userId, full_name: fullName, email });
  else await adminClient.from("profiles").update({ full_name: fullName, email }).eq("user_id", userId);

  const { data: existingRole } = await adminClient.from("user_roles").select("id").eq("user_id", userId).eq("role", "homeowner").maybeSingle();
  if (!existingRole) await adminClient.from("user_roles").insert({ user_id: userId, role: "homeowner" });

  return userId;
}

Deno.serve(async (req) => {
  if (req.method === "OPTIONS") return new Response(null, { headers: corsHeaders });

  try {
    const supabaseUrl = Deno.env.get("SUPABASE_URL")!;
    const serviceKey = Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!;
    const anonKey = Deno.env.get("SUPABASE_ANON_KEY")!;
    const adminClient = createClient(supabaseUrl, serviceKey);
    const body = await req.json();
    const { action } = body;

    if (action === "submit_request") {
      const lastName = normalize(body.last_name);
      const email = normalizeEmail(body.email);
      const unitIdentifier = normalize(body.unit_identifier || body.unit_number);
      const accountNumber = normalize(body.account_number);
      if (!lastName || !email || (!unitIdentifier && !accountNumber)) return jsonResponse({ error: "Last name, email, and either unit ID or account number are required" }, 400);
      if (!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(email)) return jsonResponse({ error: "Enter a valid email address" }, 400);

      const { unit, owner } = await findMatchingOwner(adminClient, lastName, email, unitIdentifier, accountNumber);
      const { data, error } = await adminClient.from("owner_registration_requests").insert({
        last_name: lastName,
        email,
        unit_identifier: unitIdentifier,
        account_number: accountNumber,
        association_id: owner?.association_id || unit?.association_id || null,
        unit_id: owner?.unit_id || unit?.id || null,
        owner_id: owner?.id || null,
        notes: owner ? null : "No exact owner match was found automatically.",
      }).select("id").single();
      if (error) throw error;
      return jsonResponse({ success: true, id: data.id, matched: Boolean(owner) });
    }

    if (action === "validate") {
      const unitNumber = normalize(body.unit_number);
      const accountNumber = normalize(body.account_number);
      if (!unitNumber || !accountNumber) return jsonResponse({ error: "Unit number and account number are required" }, 400);

      const unitFilters = [`unit_number.ilike.${unitNumber}`];
      if (isUuid(unitNumber)) unitFilters.push(`id.eq.${unitNumber}`);

      const { data: units, error: unitErr } = await adminClient
        .from("units")
        .select("id, unit_number, address, association_id, account_number")
        .or(unitFilters.join(","))
        .or(`account_number.ilike.${accountNumber}`);
      if (unitErr) throw unitErr;
      if (!units?.length) return jsonResponse({ error: "No matching unit found. Please check your Unit ID and Account Number." }, 404);

      const { data: owners, error: ownerErr } = await adminClient
        .from("owners")
        .select("id, first_name, last_name, email, unit_id, association_id, user_id, exclude_from_signin")
        .in("unit_id", units.map((u: any) => u.id))
        .eq("status", "active");
      if (ownerErr) throw ownerErr;
      const available = (owners || []).filter((o: any) => !o.exclude_from_signin && !o.user_id);
      if (!available.length) return jsonResponse({ error: "All owners for this unit are already registered or excluded from sign-in." }, 400);
      return jsonResponse({ owners: available.map((o: any) => ({ id: o.id, first_name: o.first_name, last_name: o.last_name, email: o.email })), unit: units[0] });
    }

    if (action === "register") {
      const email = normalizeEmail(body.email);
      const password = normalize(body.password);
      const ownerId = normalize(body.owner_id);
      if (!email || !password || !ownerId) return jsonResponse({ error: "Email, password, and owner selection are required" }, 400);

      const { data: owner, error: ownerErr } = await adminClient
        .from("owners")
        .select("id, first_name, last_name, association_id, unit_id, user_id, exclude_from_signin")
        .eq("id", ownerId)
        .single();
      if (ownerErr || !owner) return jsonResponse({ error: "Owner record not found" }, 404);
      if (owner.user_id) return jsonResponse({ error: "This owner is already linked to an account" }, 400);
      if (owner.exclude_from_signin) return jsonResponse({ error: "This owner is excluded from sign-in" }, 400);

      const userId = await createOrLinkOwnerAccount(adminClient, owner, email);
      const { error: updatePasswordError } = await adminClient.auth.admin.updateUserById(userId, { password });
      if (updatePasswordError) throw updatePasswordError;
      return jsonResponse({ success: true, user_id: userId });
    }

    if (action === "request_password_reset") {
      const email = normalizeEmail(body.email);
      const origin = normalize(body.origin) || req.headers.get("origin") || "https://avria.cloud";
      if (!email) return jsonResponse({ error: "Email is required" }, 400);
      if (!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(email)) return jsonResponse({ error: "Enter a valid email address" }, 400);

      const { data: owners, error: ownerErr } = await adminClient
        .from("owners")
        .select("id, first_name, last_name, email, association_id, unit_id, user_id, exclude_from_signin")
        .ilike("email", email)
        .eq("status", "active")
        .limit(1);
      if (ownerErr) throw ownerErr;

      const owner = (owners || []).find((o: any) => !o.exclude_from_signin && normalizeEmail(o.email) === email);
      if (owner) {
        await createOrLinkOwnerAccount(adminClient, owner, email);
        const publicClient = createClient(supabaseUrl, anonKey);
        const { error: resetError } = await publicClient.auth.resetPasswordForEmail(email, {
          redirectTo: `${origin.replace(/\/$/, "")}/reset-password`,
        });
        if (resetError) throw resetError;
      }

      return jsonResponse({ success: true });
    }

    if (action === "invite_owner" || action === "approve_request") {
      const auth = await getAuthorizedCaller(req, anonKey);
      if (auth.error) return auth.error;
      const callerClient = auth.callerClient!;
      const callerId = auth.callerId!;
      const origin = req.headers.get("origin") || "https://avria.cloud";
      let owner: any = null;
      let requestId: string | null = null;
      let email = normalizeEmail(body.email);

      if (action === "approve_request") {
        requestId = normalize(body.request_id);
        if (!requestId) return jsonResponse({ error: "Request ID is required" }, 400);
        const { data: requestRow, error: reqErr } = await adminClient.from("owner_registration_requests").select("*").eq("id", requestId).single();
        if (reqErr || !requestRow) return jsonResponse({ error: "Registration request not found" }, 404);
        email = normalizeEmail(requestRow.email);
        if (requestRow.owner_id) {
          const { data } = await adminClient.from("owners").select("id, first_name, last_name, association_id, unit_id, user_id, exclude_from_signin").eq("id", requestRow.owner_id).single();
          owner = data;
        } else {
          const match = await findMatchingOwner(adminClient, requestRow.last_name, email, requestRow.unit_identifier, requestRow.account_number);
          owner = match.owner;
        }
        if (!owner) return jsonResponse({ error: "No matching owner was found for this request" }, 400);
      } else {
        const ownerId = normalize(body.owner_id);
        if (!ownerId) return jsonResponse({ error: "Owner ID is required" }, 400);
        const { data, error } = await adminClient.from("owners").select("id, first_name, last_name, email, association_id, unit_id, user_id, exclude_from_signin").eq("id", ownerId).single();
        if (error || !data) return jsonResponse({ error: "Owner record not found" }, 404);
        owner = data;
        email = normalizeEmail(body.email || owner.email);
      }

      if (!email) return jsonResponse({ error: "Owner email is required before sending an invite" }, 400);
      if (owner.exclude_from_signin) return jsonResponse({ error: "This owner is excluded from sign-in" }, 400);

      const userId = await createOrLinkOwnerAccount(adminClient, owner, email);
      const { data: linkData, error: linkError } = await adminClient.auth.admin.generateLink({
        type: "recovery",
        email,
        options: { redirectTo: `${origin.replace(/\/$/, "")}/reset-password` },
      });
      if (linkError) throw linkError;
      const actionLink = linkData?.properties?.action_link;
      if (!actionLink) throw new Error("Could not generate account setup link");

      const html = buildActionEmailHtml({
        title: action === "approve_request" ? "Your account has been approved" : "You are invited to Avria Community Management",
        intro: action === "approve_request"
          ? "Your homeowner portal account has been approved. Click below to choose your password and sign in."
          : "You have been invited to access your homeowner portal. Click below to choose your password and get started.",
        buttonLabel: "Choose Password",
        actionLink,
      });
      const sendResult = await sendManagedEmail(callerClient, email, action === "approve_request" ? "Your account has been approved" : "Homeowner portal invitation", html);

      if (requestId) {
        await adminClient.from("owner_registration_requests").update({
          status: "approved",
          owner_id: owner.id,
          unit_id: owner.unit_id,
          association_id: owner.association_id,
          reviewed_by: callerId,
          reviewed_at: new Date().toISOString(),
          created_user_id: userId,
        }).eq("id", requestId);
      }

      return jsonResponse({ success: true, user_id: userId, email_sent: !sendResult.skipped, action_link: sendResult.skipped ? actionLink : undefined, warning: sendResult.skipped ? sendResult.reason : undefined });
    }

    if (action === "reject_request") {
      const auth = await getAuthorizedCaller(req, anonKey);
      if (auth.error) return auth.error;
      const requestId = normalize(body.request_id);
      if (!requestId) return jsonResponse({ error: "Request ID is required" }, 400);
      const { error } = await adminClient.from("owner_registration_requests").update({
        status: "rejected",
        notes: normalize(body.notes) || null,
        reviewed_by: auth.callerId,
        reviewed_at: new Date().toISOString(),
      }).eq("id", requestId);
      if (error) throw error;
      return jsonResponse({ success: true });
    }

    return jsonResponse({ error: "Invalid action" }, 400);
  } catch (err: any) {
    console.error("homeowner-signup error:", err);
    return jsonResponse({ error: err.message || "Internal server error" }, 500);
  }
});
