'use client';

import { useEffect, useMemo, useState } from 'react';
import axios from '@/network/axios';
import { getBlobErrorMessage, jsonErrorInBlobResponse } from '@/utils/helper/blobError';
import { RiFilterOffLine, RiSearchLine, RiWhatsappLine, RiDownloadLine } from '@remixicon/react';
import { Button } from '@/components/ui/button';
import { Checkbox } from '@/components/ui/checkbox';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/select';
import useInfluencerPhoneReport, {
  rowKey,
  buildParams,
  type PhoneReportRow,
} from './hooks/useInfluencerPhoneReport';
import usePhoneReportFilterOptions from './hooks/usePhoneReportFilterOptions';
import BulkSendModal from './components/BulkSendModal/BulkSendModal';

const SOURCE_LABEL: Record<string, string> = {
  admin_sheet: 'Admin sheet',
  merchant: 'Merchant added',
  profile: 'Profile',
  bio: 'Extracted from bio',
};

const SOURCE_STYLE: Record<string, string> = {
  admin_sheet: 'bg-violet-100 text-violet-700',
  merchant: 'bg-blue-100 text-blue-700',
  profile: 'bg-emerald-100 text-emerald-700',
  bio: 'bg-amber-100 text-amber-700',
};

export const InfluencerPhones = () => {
  const [currentPage, setCurrentPage] = useState(1);

  const [searchInput, setSearchInput] = useState('');
  const [search, setSearch] = useState('');
  // Multiple platforms can be active at once; sent to the API comma-separated.
  const [platforms, setPlatforms] = useState<string[]>([]);
  const [source, setSource] = useState('');
  const [countryCode, setCountryCode] = useState('');
  const [minFollowersInput, setMinFollowersInput] = useState('');
  const [maxFollowersInput, setMaxFollowersInput] = useState('');
  const [minFollowers, setMinFollowers] = useState('');
  const [maxFollowers, setMaxFollowers] = useState('');

  const platform = platforms.join(',');

  // Selection: explicit row keys, or "everything matching the filters".
  const [selected, setSelected] = useState<string[]>([]);
  const [selectAllMatching, setSelectAllMatching] = useState(false);
  const [exporting, setExporting] = useState(false);
  const [exportError, setExportError] = useState<string | null>(null);
  const [sendOpen, setSendOpen] = useState(false);

  useEffect(() => {
    const handler = setTimeout(() => setSearch(searchInput.trim()), 400);
    return () => clearTimeout(handler);
  }, [searchInput]);

  // Debounce the follower bounds so typing doesn't fire a query per keystroke.
  useEffect(() => {
    const handler = setTimeout(() => {
      setMinFollowers(minFollowersInput.trim());
      setMaxFollowers(maxFollowersInput.trim());
    }, 500);
    return () => clearTimeout(handler);
  }, [minFollowersInput, maxFollowersInput]);

  // Any filter change resets paging AND the selection (the matching set changed).
  useEffect(() => {
    setCurrentPage(1);
    setSelected([]);
    setSelectAllMatching(false);
  }, [search, platform, source, countryCode, minFollowers, maxFollowers]);

  const filters = {
    search,
    platform,
    source,
    country_code: countryCode,
    min_followers: minFollowers,
    max_followers: maxFollowers,
  };
  const { data: filterOptions } = usePhoneReportFilterOptions();
  const { data, isLoading } = useInfluencerPhoneReport({ page: currentPage, ...filters });

  const rows: PhoneReportRow[] = data?.data?.items ?? [];
  const meta = data?.data?.meta;
  const total = meta?.total ?? 0;

  const pageKeys = useMemo(() => rows.map(rowKey), [rows]);
  const allOnPageSelected = pageKeys.length > 0 && pageKeys.every((k) => selected.includes(k));

  const toggleRow = (key: string) => {
    setSelectAllMatching(false);
    setSelected((prev) =>
      prev.includes(key) ? prev.filter((k) => k !== key) : [...prev, key],
    );
  };

  const togglePage = () => {
    setSelectAllMatching(false);
    setSelected((prev) =>
      allOnPageSelected
        ? prev.filter((k) => !pageKeys.includes(k))
        : Array.from(new Set([...prev, ...pageKeys])),
    );
  };

  const hasActiveFilters = !!(
    search ||
    platform ||
    source ||
    countryCode ||
    minFollowers ||
    maxFollowers
  );
  const clearFilters = () => {
    setSearchInput('');
    setSearch('');
    setPlatforms([]);
    setSource('');
    setCountryCode('');
    setMinFollowersInput('');
    setMaxFollowersInput('');
    setMinFollowers('');
    setMaxFollowers('');
  };

  /** Quick follower-range presets. */
  const applyFollowerPreset = (min: string, max: string) => {
    setMinFollowersInput(min);
    setMaxFollowersInput(max);
  };

  const formatFollowers = (n: number | null) => {
    if (n === null || n === undefined) return '—';
    if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;
    if (n >= 1_000) return `${(n / 1_000).toFixed(1)}K`;
    return n.toLocaleString();
  };

  const togglePlatform = (p: string) =>
    setPlatforms((prev) => (prev.includes(p) ? prev.filter((x) => x !== p) : [...prev, p]));

  const recipientCount = selectAllMatching ? total : selected.length;

  /**
   * Download the CSV through axios rather than navigating to the URL.
   *
   * This used to be an <a href="/influencer-number/report/export">, which broke
   * twice over: the browser resolved that root-relative path against the
   * dashboard's own origin (so Next.js answered with its 404 page instead of
   * the API), and a plain link bypasses the axios interceptor that attaches the
   * Bearer token — the route is behind platform.admin, so it would have 401'd
   * even from the right origin.
   */
  const handleExport = async () => {
    setExportError(null);
    setExporting(true);
    try {
      const response = await axios.get('/influencer-number/report/export', {
        params: buildParams(filters),
        responseType: 'blob',
      });

      // responseType: 'blob' means an error body arrives as a Blob too, so it
      // would otherwise be saved to disk as an unreadable .csv.
      const jsonError = await jsonErrorInBlobResponse(response);
      if (jsonError) throw new Error(jsonError);

      const url = window.URL.createObjectURL(new Blob([response.data]));
      const a = document.createElement('a');
      a.href = url;
      a.download = `influencer_phones_${new Date().toISOString().slice(0, 10)}.csv`;
      document.body.appendChild(a);
      a.click();
      a.remove();
      window.URL.revokeObjectURL(url);
    } catch (err) {
      console.error('Export failed:', err);
      setExportError(await getBlobErrorMessage(err));
    } finally {
      setExporting(false);
    }
  };

  return (
    <div className="p-6">
      <div className="mb-4 flex flex-wrap items-center justify-between gap-2">
        <div>
          <h1 className="text-lg font-semibold">Influencer Phone Numbers</h1>
          <p className="text-sm text-muted-foreground">
            Every influencer with a phone number — from admin sheets, merchant
            entries, profiles and bio extraction — merged into one list.
          </p>
          {/* Live counts so the admin always knows the blast size. */}
          <div className="mt-2 flex flex-wrap items-center gap-2 text-sm">
            <span className="rounded-md bg-muted px-2 py-1">
              <strong>{total.toLocaleString()}</strong> matching
              {platforms.length > 0 && (
                <span className="text-muted-foreground">
                  {' '}
                  · {platforms.join(', ')}
                </span>
              )}
            </span>
            <span
              className={`rounded-md px-2 py-1 font-medium ${
                recipientCount > 0
                  ? 'bg-primary/10 text-primary'
                  : 'bg-muted text-muted-foreground'
              }`}
            >
              <strong>{recipientCount.toLocaleString()}</strong> selected to send
            </span>
          </div>
        </div>
        <div className="flex items-center gap-2">
          <Button variant="outline" onClick={handleExport} disabled={exporting}>
            <RiDownloadLine className="size-4" />
            {exporting ? 'Exporting…' : 'Export CSV'}
          </Button>
          {exportError && (
            <span role="alert" className="text-sm text-red-600">
              {exportError}
            </span>
          )}
          <Button disabled={recipientCount === 0} onClick={() => setSendOpen(true)}>
            <RiWhatsappLine className="size-4" />
            Send WhatsApp ({recipientCount.toLocaleString()})
          </Button>
        </div>
      </div>

      {/* Filters */}
      <div className="mb-4 rounded-lg border bg-muted/30 p-4">
        <div className="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-5">
          <div className="lg:col-span-2">
            <Label className="mb-1.5 block text-xs font-medium text-muted-foreground">
              Search
            </Label>
            <div className="relative">
              <RiSearchLine className="absolute left-2.5 top-1/2 size-4 -translate-y-1/2 text-muted-foreground" />
              <Input
                placeholder="Search handle, name or phone..."
                value={searchInput}
                onChange={(e) => setSearchInput(e.target.value)}
                className="h-9 pl-8"
              />
            </div>
          </div>

          <div className="lg:col-span-3">
            <Label className="mb-1.5 block text-xs font-medium text-muted-foreground">
              Platform {platforms.length > 0 && `(${platforms.length} selected)`}
            </Label>
            {/* Multi-select: several platforms can be active at once. */}
            <div className="flex flex-wrap gap-1.5">
              <button
                type="button"
                onClick={() => setPlatforms([])}
                className={`rounded-md border px-2.5 py-1 text-xs font-medium capitalize transition ${
                  platforms.length === 0
                    ? 'border-primary bg-primary text-primary-foreground'
                    : 'bg-background hover:bg-muted'
                }`}
              >
                All
              </button>
              {(filterOptions?.platforms ?? []).map((p) => {
                const active = platforms.includes(p);
                return (
                  <button
                    key={p}
                    type="button"
                    onClick={() => togglePlatform(p)}
                    className={`rounded-md border px-2.5 py-1 text-xs font-medium capitalize transition ${
                      active
                        ? 'border-primary bg-primary text-primary-foreground'
                        : 'bg-background hover:bg-muted'
                    }`}
                  >
                    {p}
                  </button>
                );
              })}
            </div>
          </div>

          <div>
            <Label className="mb-1.5 block text-xs font-medium text-muted-foreground">
              Source
            </Label>
            <Select
              value={source || 'all'}
              onValueChange={(v) => setSource(v === 'all' ? '' : v)}
            >
              <SelectTrigger className="h-9">
                <SelectValue placeholder="All sources" />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="all">All sources</SelectItem>
                {(filterOptions?.sources ?? []).map((s) => (
                  <SelectItem key={s} value={s}>
                    {SOURCE_LABEL[s] ?? s}
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
          </div>

          <div>
            <Label className="mb-1.5 block text-xs font-medium text-muted-foreground">
              Country code
            </Label>
            <Select
              value={countryCode || 'all'}
              onValueChange={(v) => setCountryCode(v === 'all' ? '' : v)}
            >
              <SelectTrigger className="h-9">
                <SelectValue placeholder="All" />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="all">All</SelectItem>
                {(filterOptions?.country_codes ?? []).map((c) => (
                  <SelectItem key={c} value={c}>
                    {c}
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
          </div>
        </div>

        {/* Follower range */}
        <div className="mt-3 border-t pt-3">
          <Label className="mb-1.5 block text-xs font-medium text-muted-foreground">
            Followers
          </Label>
          <div className="flex flex-wrap items-center gap-2">
            <Input
              type="number"
              min={0}
              placeholder="Min"
              value={minFollowersInput}
              onChange={(e) => setMinFollowersInput(e.target.value)}
              className="h-9 w-32"
            />
            <span className="text-sm text-muted-foreground">to</span>
            <Input
              type="number"
              min={0}
              placeholder="Max"
              value={maxFollowersInput}
              onChange={(e) => setMaxFollowersInput(e.target.value)}
              className="h-9 w-32"
            />
            <div className="ml-2 flex flex-wrap gap-1.5">
              {[
                { label: '1K–10K', min: '1000', max: '10000' },
                { label: '10K–100K', min: '10000', max: '100000' },
                { label: '100K–1M', min: '100000', max: '1000000' },
                { label: '1M+', min: '1000000', max: '' },
              ].map((p) => {
                const active = minFollowersInput === p.min && maxFollowersInput === p.max;
                return (
                  <button
                    key={p.label}
                    type="button"
                    onClick={() => applyFollowerPreset(p.min, p.max)}
                    className={`rounded-md border px-2.5 py-1 text-xs font-medium transition ${
                      active
                        ? 'border-primary bg-primary text-primary-foreground'
                        : 'bg-background hover:bg-muted'
                    }`}
                  >
                    {p.label}
                  </button>
                );
              })}
            </div>
          </div>
          {(minFollowers || maxFollowers) && (
            <p className="mt-1.5 text-xs text-muted-foreground">
              Influencers with no synced follower count are excluded while a
              follower range is active.
            </p>
          )}
        </div>

        {hasActiveFilters && (
          <div className="mt-3">
            <Button variant="ghost" size="sm" onClick={clearFilters}>
              <RiFilterOffLine className="size-4" />
              Clear filters
            </Button>
          </div>
        )}
      </div>

      {/* Select-all-matching banner */}
      {selected.length > 0 && allOnPageSelected && !selectAllMatching && total > rows.length && (
        <div className="mb-3 flex flex-wrap items-center justify-between gap-3 rounded-md border border-blue-300 bg-blue-50 px-4 py-3 text-sm">
          <span>
            Only the <strong>{rows.length}</strong> influencers on{' '}
            <strong>this page</strong> are selected — the other{' '}
            {(total - rows.length).toLocaleString()} matching your filters are{' '}
            <strong>not</strong> included.
          </span>
          <Button size="sm" onClick={() => setSelectAllMatching(true)}>
            Select all {total.toLocaleString()} matching
          </Button>
        </div>
      )}
      {selectAllMatching && (
        <div className="mb-3 rounded-md border bg-blue-50 px-4 py-2 text-sm">
          All <strong>{total.toLocaleString()}</strong> influencers matching the current
          filters are selected.{' '}
          <button
            className="font-medium text-blue-700 underline"
            onClick={() => {
              setSelectAllMatching(false);
              setSelected([]);
            }}
          >
            Clear selection
          </button>
        </div>
      )}

      {/* Table */}
      <div className="overflow-x-auto rounded-lg border">
        <table className="w-full text-sm">
          <thead className="bg-muted/50 text-left">
            <tr>
              <th className="w-10 p-3">
                <Checkbox
                  checked={allOnPageSelected || selectAllMatching}
                  onCheckedChange={togglePage}
                  aria-label="Select all on page"
                />
              </th>
              <th className="p-3 font-medium">Handle</th>
              <th className="p-3 font-medium">Name</th>
              <th className="p-3 font-medium">Followers</th>
              <th className="p-3 font-medium">Platform</th>
              <th className="p-3 font-medium">Phone</th>
              <th className="p-3 font-medium">Source</th>
            </tr>
          </thead>
          <tbody>
            {isLoading ? (
              <tr>
                <td colSpan={7} className="p-8 text-center text-muted-foreground">
                  Loading...
                </td>
              </tr>
            ) : rows.length === 0 ? (
              <tr>
                <td colSpan={7} className="p-8 text-center text-muted-foreground">
                  No influencers with phone numbers match these filters.
                </td>
              </tr>
            ) : (
              rows.map((r) => {
                const key = rowKey(r);
                return (
                  <tr key={key} className="border-t hover:bg-muted/30">
                    <td className="p-3">
                      <Checkbox
                        checked={selectAllMatching || selected.includes(key)}
                        onCheckedChange={() => toggleRow(key)}
                        aria-label={`Select ${r.username}`}
                      />
                    </td>
                    <td className="p-3 font-medium">@{(r.username || '').replace(/^@/, '')}</td>
                    <td className="p-3 text-muted-foreground">{r.name || '—'}</td>
                    <td
                      className="p-3 font-medium"
                      title={r.followers != null ? r.followers.toLocaleString() : undefined}
                    >
                      {formatFollowers(r.followers)}
                    </td>
                    <td className="p-3 capitalize">{r.platform}</td>
                    <td className="p-3 font-mono text-xs">{r.phone}</td>
                    <td className="p-3">
                      <span
                        className={`rounded-md px-2 py-0.5 text-xs font-medium ${
                          SOURCE_STYLE[r.source] ?? 'bg-gray-100 text-gray-700'
                        }`}
                      >
                        {SOURCE_LABEL[r.source] ?? r.source}
                      </span>
                    </td>
                  </tr>
                );
              })
            )}
          </tbody>
        </table>
      </div>

      {/* Pagination */}
      {meta && meta.last_page > 1 && (
        <div className="mt-4 flex items-center justify-between">
          <p className="text-sm text-muted-foreground">
            Page {meta.current_page} of {meta.last_page} · {total.toLocaleString()} total
          </p>
          <div className="flex gap-2">
            <Button
              variant="outline"
              size="sm"
              disabled={currentPage <= 1}
              onClick={() => setCurrentPage((p) => p - 1)}
            >
              Previous
            </Button>
            <Button
              variant="outline"
              size="sm"
              disabled={currentPage >= meta.last_page}
              onClick={() => setCurrentPage((p) => p + 1)}
            >
              Next
            </Button>
          </div>
        </div>
      )}

      <BulkSendModal
        open={sendOpen}
        onOpenChange={setSendOpen}
        selected={selected}
        selectAll={selectAllMatching}
        matchingTotal={total}
        filters={filters}
      />
    </div>
  );
};

export default InfluencerPhones;
