/**
 * Server-side project data fetching for Next.js Server Components.
 *
 * Uses `fetch` directly (no browser-only helpers) so it can run
 * inside `generateMetadata`, `generateStaticParams`, `sitemap()`, etc.
 */

import type {
  ProjectDetail,
  ProjectMedia,
  ProjectSummary,
  PaginatedResult,
} from './du-an-api';

const API_BASE_URL = process.env['NEXT_PUBLIC_API_URL'] || 'http://localhost:3001/api/v1';

/**
 * The backend detail endpoint currently returns a thin projection: the
 * repository's raw row run through `shapeProject`, which strips `media` and
 * omits the richer fields (`blocks`, `amenities`, `priceRanges`, …) that the
 * frontend detail page consumes.
 *
 * Until the backend detail endpoint is enriched, normalize the payload here
 * so the UI never crashes on missing arrays or mis-keyed developer fields.
 */
function normalizeProjectDetail(raw: unknown): ProjectDetail | null {
  if (!raw || typeof raw !== 'object') return null;
  const r = raw as Record<string, unknown>;

  // Developer: backend currently returns `{ id, name, logo }`; frontend expects
  // `{ id, name, logoUrl, totalProjects }`.
  const rawDeveloper = (r['developer'] ?? {}) as Record<string, unknown>;
  const developer = {
    id: typeof rawDeveloper['id'] === 'string' ? rawDeveloper['id'] : '',
    name: typeof rawDeveloper['name'] === 'string' ? rawDeveloper['name'] : '',
    logoUrl:
      (rawDeveloper['logoUrl'] as string | null | undefined) ??
      (rawDeveloper['logo'] as string | null | undefined) ??
      null,
    totalProjects:
      typeof rawDeveloper['totalProjects'] === 'number' ? rawDeveloper['totalProjects'] : 0,
  };

  // Media: may be absent (stripped by backend), or present as a raw JSON array.
  // Backend returns media as either `string[]` (raw URLs from the seed JSON
  // column) or `{ id, url, type, order, caption }[]` once richer data lands.
  // Handle both shapes and drop entries without a resolvable URL so we never
  // feed an empty string to `<Image src>`.
  const rawMediaArr = Array.isArray(r['media']) ? (r['media'] as unknown[]) : [];
  const media: ProjectMedia[] = rawMediaArr
    .map((entry, idx): ProjectMedia | null => {
      if (typeof entry === 'string') {
        if (!entry) return null;
        return { id: `media-${idx}`, url: entry, type: 'image', order: idx, caption: null };
      }
      if (entry && typeof entry === 'object') {
        const m = entry as Record<string, unknown>;
        const url = typeof m['url'] === 'string' ? m['url'] : '';
        if (!url) return null;
        return {
          id: typeof m['id'] === 'string' ? m['id'] : `media-${idx}`,
          url,
          type:
            m['type'] === 'video' ||
            m['type'] === 'master_plan' ||
            m['type'] === 'document' ||
            m['type'] === 'image'
              ? (m['type'] as ProjectMedia['type'])
              : 'image',
          order: typeof m['order'] === 'number' ? m['order'] : idx,
          caption: typeof m['caption'] === 'string' ? m['caption'] : null,
        };
      }
      return null;
    })
    .filter((m): m is ProjectMedia => m !== null);

  const asArray = <T>(v: unknown): T[] => (Array.isArray(v) ? (v as T[]) : []);

  // Amenities in the DB are a JSON string[]; the frontend type expects
  // `{ id, name, icon, category }`. Normalize strings into objects so the
  // AmenitiesTab render has stable keys + a displayable name.
  const rawAmenities = Array.isArray(r['amenities']) ? (r['amenities'] as unknown[]) : [];
  const amenities = rawAmenities.map((a, idx) => {
    if (typeof a === 'string') {
      return { id: `amenity-${idx}`, name: a, icon: '', category: 'Tiện ích' };
    }
    if (a && typeof a === 'object') {
      const o = a as Record<string, unknown>;
      return {
        id: typeof o['id'] === 'string' ? o['id'] : `amenity-${idx}`,
        name: typeof o['name'] === 'string' ? o['name'] : '',
        icon: typeof o['icon'] === 'string' ? o['icon'] : '',
        category: typeof o['category'] === 'string' ? o['category'] : 'Tiện ích',
      };
    }
    return { id: `amenity-${idx}`, name: '', icon: '', category: 'Tiện ích' };
  });

  return {
    id: String(r['id'] ?? ''),
    slug: String(r['slug'] ?? ''),
    name: String(r['name'] ?? ''),
    status: (r['status'] as ProjectDetail['status']) ?? 'PLANNING',
    developer,
    city: String(r['city'] ?? ''),
    district: String(r['district'] ?? ''),
    address: String(r['address'] ?? ''),
    latitude: typeof r['latitude'] === 'number' ? (r['latitude'] as number) : null,
    longitude: typeof r['longitude'] === 'number' ? (r['longitude'] as number) : null,
    thumbnailUrl:
      (r['thumbnailUrl'] as string | null | undefined) ??
      media[0]?.url ??
      null,
    totalArea: typeof r['totalArea'] === 'number' ? (r['totalArea'] as number) : 0,
    totalUnits: typeof r['totalUnits'] === 'number' ? (r['totalUnits'] as number) : 0,
    propertyTypes: asArray<ProjectDetail['propertyTypes'][number]>(r['propertyTypes']),
    minPrice: (r['minPrice'] as string | null | undefined) ?? null,
    maxPrice: (r['maxPrice'] as string | null | undefined) ?? null,
    completionDate: (r['completionDate'] as string | null | undefined) ?? null,
    createdAt: String(r['createdAt'] ?? new Date().toISOString()),
    description: typeof r['description'] === 'string' ? (r['description'] as string) : '',
    media,
    blocks: asArray(r['blocks']),
    amenities,
    priceRanges: asArray(r['priceRanges']),
    priceHistory: asArray(r['priceHistory']),
    neighborhoodScores: asArray(r['neighborhoodScores']),
    pois: asArray(r['pois']),
    documents: asArray(r['documents']),
    linkedListingCount:
      typeof r['linkedListingCount'] === 'number' ? (r['linkedListingCount'] as number) : 0,
    suitableFor: Array.isArray(r['suitableFor'])
      ? (r['suitableFor'] as unknown[]).filter((v): v is string => typeof v === 'string')
      : [],
    whyThisLocation:
      typeof r['whyThisLocation'] === 'string' ? (r['whyThisLocation'] as string) : null,
  };
}

/**
 * Fetch a single project by slug — server-only.
 * Returns `null` when the project is not found (404) so callers can `notFound()`.
 */
export async function fetchProjectBySlug(slug: string): Promise<ProjectDetail | null> {
  try {
    const res = await fetch(`${API_BASE_URL}/projects/${slug}`, {
      next: { revalidate: 300 }, // ISR: re-validate every 5 min
    });

    if (!res.ok) return null;
    const raw = (await res.json()) as unknown;
    return normalizeProjectDetail(raw);
  } catch {
    return null;
  }
}

/**
 * Fetch active projects — server-only, used by the dynamic sitemap.
 */
export async function fetchProjects(params: {
  page?: number;
  limit?: number;
  city?: string;
  status?: string;
}): Promise<PaginatedResult<ProjectSummary>> {
  const query = new URLSearchParams({
    page: String(params.page ?? 1),
    limit: String(params.limit ?? 100),
  });
  if (params.city) query.append('city', params.city);
  if (params.status) query.append('status', params.status);

  try {
    const res = await fetch(`${API_BASE_URL}/projects?${query}`, {
      next: { revalidate: 3600 }, // re-validate every hour for sitemap
    });

    if (!res.ok) {
      return { data: [], total: 0, page: 1, limit: 100, totalPages: 0 };
    }

    return (await res.json()) as PaginatedResult<ProjectSummary>;
  } catch {
    return { data: [], total: 0, page: 1, limit: 100, totalPages: 0 };
  }
}
