import api from './api';
import { getArticles } from './articles';
import { getPlayers } from './public';
import { getUpcomingEvents } from './eventService';
import { getSponsors } from './sponsors';
import facrApi from './facr/facrApi';
import { getRelatedClubs, RelatedClub } from './relatedClubs';

export interface SearchResult {
  type: 'club' | 'match' | 'match_past' | 'article' | 'player' | 'event' | 'sponsor' | 'team' | 'contact' | 'gallery';
  id: string | number;
  title: string;
  subtitle?: string;
  description?: string;
  image_url?: string;
  logo_url?: string;
  url?: string;
  date?: string;
  time?: string;
  score?: number;
  metadata?: Record<string, any>;
}

export interface SearchResults {
  clubs: SearchResult[];
  matches: SearchResult[];
  matchesPast: SearchResult[];
  articles: SearchResult[];
  players: SearchResult[];
  events: SearchResult[];
  sponsors: SearchResult[];
  teams: SearchResult[];
  contacts: SearchResult[];
  gallery: SearchResult[];
  total: number;
}

// Enhanced scoring function for relevance with keyword support
const scoreMatch = (text: string, query: string): number => {
  const t = (text || '').toLowerCase();
  const q = (query || '').toLowerCase();
  if (!t || !q) return 0;
  
  // Exact match - highest score
  if (t === q) return 100;
  
  // Starts with query - very high score
  if (t.startsWith(q)) return 80;
  
  // Contains query as whole substring
  const idx = t.indexOf(q);
  if (idx >= 0) return 60 - Math.min(idx, 30);
  
  // Keyword matching - split query into words and check each
  const keywords = q.split(/\s+/).filter(k => k.length > 1);
  if (keywords.length > 1) {
    let matchedKeywords = 0;
    let totalScore = 0;
    
    for (const keyword of keywords) {
      if (t.includes(keyword)) {
        matchedKeywords++;
        const keywordIdx = t.indexOf(keyword);
        // Score based on position and keyword match
        totalScore += (keywordIdx === 0 ? 25 : 15 - Math.min(keywordIdx, 10));
      }
    }
    
    // If at least half the keywords match, return proportional score
    if (matchedKeywords >= keywords.length / 2) {
      return Math.min(55, totalScore * (matchedKeywords / keywords.length));
    }
  }
  
  // Partial character matching for typos/fuzzy search
  const chars = q.split('');
  let lastIdx = -1;
  let matched = 0;
  for (const char of chars) {
    const charIdx = t.indexOf(char, lastIdx + 1);
    if (charIdx > lastIdx) {
      matched++;
      lastIdx = charIdx;
    }
  }
  
  if (matched >= chars.length * 0.8) {
    return Math.min(25, Math.floor((matched / chars.length) * 25));
  }
  
  return 0;
};

// Resolve backend URLs for assets
const resolveBackendUrl = (path: string): string => {
  try {
    if (/^https?:\/\//i.test(path)) return path;
    if (path.startsWith('/cache') || path.startsWith('/uploads') || path.startsWith('/api/')) {
      const base = process.env.REACT_APP_API_BASE_URL || process.env.REACT_APP_API_URL || 'http://localhost:8080/api/v1';
      const origin = new URL(base).origin;
      return new URL(path, origin).toString();
    }
    return path;
  } catch {
    return path;
  }
};

const normalizeName = (value: string) =>
  String(value || '')
    .normalize('NFD')
    .replace(/[\u0300-\u036f]/g, '')
    .replace(/\s+/g, ' ')
    .trim()
    .toLowerCase();

export async function searchAll(query: string): Promise<SearchResults> {
  if (!query || query.trim().length === 0) {
    return {
      clubs: [],
      matches: [],
      matchesPast: [],
      articles: [],
      players: [],
      events: [],
      sponsors: [],
      teams: [],
      contacts: [],
      gallery: [],
      total: 0,
    };
  }

  const q = query.trim().toLowerCase();

  try {
    const relatedClubsPromise = getRelatedClubs();
    // Fetch all data in parallel
    const [
      relatedClubsRes,
      clubsRes,
      matchesRes,
      matchesPastRes,
      articlesRes,
      playersRes,
      eventsRes,
      sponsorsRes,
      teamsRes,
      contactsRes,
      galleryRes,
    ] = await Promise.allSettled([
      relatedClubsPromise,
      // Clubs from FACR
      facrApi.searchClubs(query).catch(() => ({ results: [] })),
      
      // Matches (upcoming)
      (async () => {
        const url = resolveBackendUrl(`/api/v1/matches?q=${encodeURIComponent(query)}`);
        const res = await fetch(url, { cache: 'no-cache' });
        if (!res.ok) return [];
        return await res.json();
      })(),
      
      // Matches (past)
      (async () => {
        const url = resolveBackendUrl(`/api/v1/matches/history?q=${encodeURIComponent(query)}`);
        const res = await fetch(url, { cache: 'no-cache' });
        if (!res.ok) return [];
        return await res.json();
      })(),
      
      // Articles
      getArticles({ q: query, published: true, page: 1, page_size: 50 }),
      
      // Players
      getPlayers(),
      
      // Events
      getUpcomingEvents(),
      
      // Sponsors
      getSponsors(),
      
      // Teams
      (async () => {
        const res = await api.get('/teams');
        return Array.isArray(res.data) ? res.data : res.data?.data || [];
      })(),
      
      // Contacts
      (async () => {
        try {
          const res = await api.get('/contacts');
          // Backend returns { categories: {...}, uncategorized: [...] }
          // Flatten into a single array
          const grouped = res.data?.categories || {};
          const uncategorized = res.data?.uncategorized || [];
          const allContacts = [...uncategorized];
          Object.values(grouped).forEach((contacts: any) => {
            if (Array.isArray(contacts)) {
              allContacts.push(...contacts);
            }
          });
          return allContacts;
        } catch {
          return [];
        }
      })(),
      
      // Gallery albums
      (async () => {
        try {
          const res = await api.get('/gallery/albums');
          return Array.isArray(res.data) ? res.data : res.data?.data || res.data?.albums || [];
        } catch {
          return [];
        }
      })(),
    ]);

    const relatedClubs: RelatedClub[] = relatedClubsRes.status === 'fulfilled' ? relatedClubsRes.value : [];
    const relatedById = new Map<string, RelatedClub>();
    const relatedByName = new Map<string, RelatedClub>();
    relatedClubs.forEach((club) => {
      const idKey = String(club.id || '').toLowerCase();
      if (idKey) relatedById.set(idKey, club);
      const nameKey = normalizeName(club.name);
      if (nameKey) relatedByName.set(nameKey, club);
    });
    const hasRelatedFilter = relatedById.size > 0 || relatedByName.size > 0;

    // Process clubs
    const clubsData = clubsRes.status === 'fulfilled' ? (clubsRes.value as any)?.results || [] : [];
    const clubs: SearchResult[] = clubsData
      .filter((c: any) => {
        // Filter out clubs with no name or empty name
        const name = String(c.name || '').trim();
        if (!name) return false;
        
        if (!hasRelatedFilter) return true;
        const idKey = String(c.club_id || c.id || '').toLowerCase();
        const nameKey = normalizeName(c.name);
        return (idKey && relatedById.has(idKey)) || (nameKey && relatedByName.has(nameKey));
      })
      .map((c: any) => {
        const idKey = String(c.club_id || c.id || '').toLowerCase();
        const nameKey = normalizeName(c.name);
        const related = (idKey && relatedById.get(idKey)) || (nameKey && relatedByName.get(nameKey)) || null;
        const score = Math.max(scoreMatch(c.name, q), scoreMatch(c.category || '', q));
        const logo = related?.logo_url || c.logo_url;
        const subtitle = related?.competition || c.category || c.club_type;
        return {
          type: 'club' as const,
          id: c.club_id || c.id,
          title: c.name,
          subtitle,
          logo_url: logo ? resolveBackendUrl(logo) : undefined,
          metadata: {
            club_type: c.club_type,
            last_played_iso: related?.last_played_iso,
            matches_played: related?.matches_played,
          },
          score,
        } as SearchResult;
      })
      .sort((a: SearchResult, b: SearchResult) => (b.score || 0) - (a.score || 0));

    const matchPassesFilter = (home?: string, away?: string, homeId?: string, awayId?: string) => {
      if (!hasRelatedFilter) return true;
      const homeName = normalizeName(home || '');
      const awayName = normalizeName(away || '');
      if (homeName && relatedByName.has(homeName)) return true;
      if (awayName && relatedByName.has(awayName)) return true;
      const homeKey = String(homeId || '').toLowerCase();
      const awayKey = String(awayId || '').toLowerCase();
      if (homeKey && relatedById.has(homeKey)) return true;
      if (awayKey && relatedById.has(awayKey)) return true;
      return false;
    };

    // Process matches (upcoming)
    const matchesData = matchesRes.status === 'fulfilled' ? matchesRes.value : [];
    const matches: SearchResult[] = (Array.isArray(matchesData) ? matchesData : [])
      .filter((m: any) => matchPassesFilter(m.home, m.away, m.home_id || m.homeId, m.away_id || m.awayId))
      .map((m: any, idx: number) => ({
        type: 'match' as const,
        id: m.id || idx,
        title: `${m.home || 'TBD'} vs ${m.away || 'TBD'}`,
        subtitle: m.competition || m.competition_name || m.league,
        date: m.date,
        time: m.time,
        metadata: {
          home: m.home,
          away: m.away,
          home_logo_url: m.home_logo_url,
          away_logo_url: m.away_logo_url,
          venue: m.venue,
        },
        score: Math.max(
          scoreMatch(m.home || '', q),
          scoreMatch(m.away || '', q),
          scoreMatch(m.venue || '', q),
          scoreMatch(m.competition || m.competition_name || m.league || '', q)
        ),
      })).sort((a: SearchResult, b: SearchResult) => (b.score || 0) - (a.score || 0));

    // Process matches (past)
    const matchesPastData = matchesPastRes.status === 'fulfilled' ? matchesPastRes.value : [];
    const matchesPast: SearchResult[] = (Array.isArray(matchesPastData) ? matchesPastData : [])
      .filter((m: any) => matchPassesFilter(m.home, m.away, m.home_id || m.homeId, m.away_id || m.awayId))
      .map((m: any, idx: number) => ({
        type: 'match_past' as const,
        id: `past-${m.id || idx}`,
        title: `${m.home || 'TBD'} vs ${m.away || 'TBD'}`,
        subtitle: m.competition || m.competition_name || m.league,
        date: m.date,
        time: m.time,
        metadata: {
          home: m.home,
          away: m.away,
          home_logo_url: m.home_logo_url,
          away_logo_url: m.away_logo_url,
          venue: m.venue,
        },
        score: Math.max(
          scoreMatch(m.home || '', q),
          scoreMatch(m.away || '', q),
          scoreMatch(m.venue || '', q),
          scoreMatch(m.competition || m.competition_name || m.league || '', q)
        ),
      })).sort((a: SearchResult, b: SearchResult) => (b.score || 0) - (a.score || 0));

    // Process articles
    const articlesData = articlesRes.status === 'fulfilled' ? articlesRes.value?.data || [] : [];
    const articles: SearchResult[] = articlesData
      .filter((a: any) => {
        const titleMatch = scoreMatch(a.title || '', q);
        const excerptMatch = scoreMatch(a.excerpt || '', q);
        const contentMatch = scoreMatch(a.content || '', q);
        return titleMatch > 0 || excerptMatch > 0 || contentMatch > 0;
      })
      .map((a: any) => ({
        type: 'article' as const,
        id: a.id,
        title: a.title,
        description: a.excerpt,
        image_url: a.image_url,
        url: `/blog/${a.slug || a.id}`,
        date: a.published_at || a.created_at,
        score: Math.max(
          scoreMatch(a.title || '', q),
          scoreMatch(a.excerpt || '', q) * 0.7,
          scoreMatch(a.content || '', q) * 0.3
        ),
      }))
      .sort((a: SearchResult, b: SearchResult) => (b.score || 0) - (a.score || 0));

    // Process players
    const playersData = playersRes.status === 'fulfilled' ? playersRes.value : [];
    const players: SearchResult[] = (Array.isArray(playersData) ? playersData : [])
      .filter((p: any) => {
        const fullName = `${p.first_name || ''} ${p.last_name || ''}`;
        const nameMatch = scoreMatch(fullName, q);
        const positionMatch = scoreMatch(p.position || '', q);
        return nameMatch > 0 || positionMatch > 0;
      })
      .map((p: any) => ({
        type: 'player' as const,
        id: p.id,
        title: `${p.first_name} ${p.last_name}`,
        subtitle: p.position,
        image_url: p.image_url,
        url: `/hraci/${p.id}`,
        metadata: { jersey_number: p.jersey_number },
        score: Math.max(
          scoreMatch(`${p.first_name} ${p.last_name}`, q),
          scoreMatch(p.position || '', q)
        ),
      }))
      .sort((a: any, b: any) => (b.score || 0) - (a.score || 0));

    // Process events
    const eventsData = eventsRes.status === 'fulfilled' ? eventsRes.value : [];
    const events: SearchResult[] = (Array.isArray(eventsData) ? eventsData : [])
      .filter((e: any) => {
        const titleMatch = scoreMatch(e.title || '', q);
        const descMatch = scoreMatch(e.description || '', q);
        const locationMatch = scoreMatch(e.location || '', q);
        return titleMatch > 0 || descMatch > 0 || locationMatch > 0;
      })
      .map((e: any) => ({
        type: 'event' as const,
        id: e.id,
        title: e.title,
        description: e.description,
        date: e.event_date,
        time: e.event_time,
        metadata: { location: e.location },
        score: Math.max(
          scoreMatch(e.title || '', q),
          scoreMatch(e.description || '', q) * 0.7,
          scoreMatch(e.location || '', q) * 0.5
        ),
      }))
      .sort((a: any, b: any) => (b.score || 0) - (a.score || 0));

    // Process sponsors
    const sponsorsData = sponsorsRes.status === 'fulfilled' ? sponsorsRes.value : [];
    const sponsors: SearchResult[] = (Array.isArray(sponsorsData) ? sponsorsData : [])
      .filter((s: any) => {
        const nameMatch = scoreMatch(s.name || '', q);
        return nameMatch > 0;
      })
      .map((s: any) => ({
        type: 'sponsor' as const,
        id: s.id,
        title: s.name,
        logo_url: s.logo_url,
        url: s.website_url,
        score: scoreMatch(s.name || '', q),
      }))
      .sort((a: any, b: any) => (b.score || 0) - (a.score || 0));

    // Process teams
    const teamsData = teamsRes.status === 'fulfilled' ? teamsRes.value : [];
    const teams: SearchResult[] = (Array.isArray(teamsData) ? teamsData : [])
      .filter((t: any) => {
        // Filter out teams with no name or empty name
        const name = String(t.name || '').trim();
        if (!name) return false;
        
        const nameMatch = scoreMatch(t.name || '', q);
        const shortMatch = scoreMatch(t.short_name || '', q);
        return nameMatch > 0 || shortMatch > 0;
      })
      .map((t: any) => ({
        type: 'team' as const,
        id: t.id,
        title: t.name,
        subtitle: t.short_name,
        logo_url: t.logo_url,
        description: t.description,
        score: Math.max(scoreMatch(t.name || '', q), scoreMatch(t.short_name || '', q)),
      }))
      .sort((a: any, b: any) => (b.score || 0) - (a.score || 0));

    // Process contacts
    const contactsData = contactsRes.status === 'fulfilled' ? contactsRes.value : [];
    const contacts: SearchResult[] = (Array.isArray(contactsData) ? contactsData : [])
      .filter((c: any) => {
        const nameMatch = scoreMatch(c.name || '', q);
        const positionMatch = scoreMatch(c.position || '', q);
        const emailMatch = scoreMatch(c.email || '', q);
        return nameMatch > 0 || positionMatch > 0 || emailMatch > 0;
      })
      .map((c: any) => ({
        type: 'contact' as const,
        id: c.id,
        title: c.name,
        subtitle: c.position,
        description: c.description,
        image_url: c.image_url,
        metadata: { email: c.email, phone: c.phone },
        score: Math.max(
          scoreMatch(c.name || '', q),
          scoreMatch(c.position || '', q),
          scoreMatch(c.email || '', q) * 0.5
        ),
      }))
      .sort((a: any, b: any) => (b.score || 0) - (a.score || 0));

    // Process gallery albums
    const galleryData = galleryRes.status === 'fulfilled' ? galleryRes.value : [];
    const gallery: SearchResult[] = (Array.isArray(galleryData) ? galleryData : [])
      .filter((g: any) => {
        const titleMatch = scoreMatch(g.title || g.name || '', q);
        const descMatch = scoreMatch(g.description || '', q);
        return titleMatch > 0 || descMatch > 0;
      })
      .map((g: any) => ({
        type: 'gallery' as const,
        id: g.id,
        title: g.title || g.name,
        description: g.description,
        image_url: g.cover_url || g.thumbnail_url,
        url: `/galerie/${g.id}`,
        metadata: { photo_count: g.photo_count },
        score: Math.max(
          scoreMatch(g.title || g.name || '', q),
          scoreMatch(g.description || '', q) * 0.7
        ),
      }))
      .sort((a: any, b: any) => (b.score || 0) - (a.score || 0));

    const total =
      clubs.length +
      matches.length +
      matchesPast.length +
      articles.length +
      players.length +
      events.length +
      sponsors.length +
      teams.length +
      contacts.length +
      gallery.length;

    return {
      clubs,
      matches,
      matchesPast,
      articles,
      players,
      events,
      sponsors,
      teams,
      contacts,
      gallery,
      total,
    };
  } catch (error) {
    console.error('Search error:', error);
    return {
      clubs: [],
      matches: [],
      matchesPast: [],
      articles: [],
      players: [],
      events: [],
      sponsors: [],
      teams: [],
      contacts: [],
      gallery: [],
      total: 0,
    };
  }
}
