import { fireEvent, render, screen } from '@testing-library/react';
import { describe, it, expect, vi } from 'vitest';

import EventCard, { CalendarEntry } from './EventCard';

const mockEntry: CalendarEntry = {
  id: 1,
  title: 'Update homepage content',
  description: 'Refresh the homepage content based on freshness recommendations',
  due_date: '2026-03-01T12:00:00Z',
  scheduled_date: '2026-03-01T12:00:00Z',
  status: 'planned',
  source_type: 'freshness_recommendation',
  source_id: 123,
  page_url: 'https://example.com/homepage',
  metadata: { priority: 'high' },
};

describe('EventCard', () => {
  describe('Rendering', () => {
    it('renders entry title', () => {
      render(<EventCard entry={mockEntry} siteId={1} />);
      expect(screen.getByText('Update homepage content')).toBeInTheDocument();
    });

    it('renders entry description', () => {
      render(<EventCard entry={mockEntry} siteId={1} />);
      expect(screen.getByText(/Refresh the homepage content/)).toBeInTheDocument();
    });

    it('renders due date', () => {
      render(<EventCard entry={mockEntry} siteId={1} />);
      expect(screen.getByText(/Due: Mar 1, 2026/)).toBeInTheDocument();
    });

    it('renders page URL as link', () => {
      render(<EventCard entry={mockEntry} siteId={1} />);
      const link = screen.getByRole('link');
      expect(link).toHaveAttribute('href', 'https://example.com/homepage');
      expect(link).toHaveAttribute('target', '_blank');
      expect(link).toHaveAttribute('rel', 'noopener noreferrer');
    });

    it('renders without description', () => {
      const entryWithoutDescription = { ...mockEntry, description: null };
      render(<EventCard entry={entryWithoutDescription} siteId={1} />);
      expect(screen.getByText('Update homepage content')).toBeInTheDocument();
    });

    it('renders without page URL', () => {
      const entryWithoutUrl = { ...mockEntry, page_url: null };
      render(<EventCard entry={entryWithoutUrl} siteId={1} />);
      expect(screen.queryByRole('link')).not.toBeInTheDocument();
    });

    it('renders without scheduled date', () => {
      const entryWithoutScheduled = { ...mockEntry, scheduled_date: null };
      render(<EventCard entry={entryWithoutScheduled} siteId={1} />);
      expect(screen.getByText('Update homepage content')).toBeInTheDocument();
    });
  });

  describe('Status Badges', () => {
    it('renders Planned badge for planned status', () => {
      render(<EventCard entry={{ ...mockEntry, status: 'planned' }} siteId={1} />);
      expect(screen.getByText('Planned')).toBeInTheDocument();
    });

    it('renders In Progress badge for in_progress status', () => {
      render(<EventCard entry={{ ...mockEntry, status: 'in_progress' }} siteId={1} />);
      expect(screen.getByText('In Progress')).toBeInTheDocument();
    });

    it('renders Completed badge for completed status', () => {
      render(<EventCard entry={{ ...mockEntry, status: 'completed' }} siteId={1} />);
      expect(screen.getByText('Completed')).toBeInTheDocument();
    });

    it('renders Overdue badge for overdue status', () => {
      render(<EventCard entry={{ ...mockEntry, status: 'overdue' }} siteId={1} />);
      expect(screen.getByText('Overdue')).toBeInTheDocument();
    });

    it('shows past due indicator for overdue status', () => {
      render(<EventCard entry={{ ...mockEntry, status: 'overdue' }} siteId={1} />);
      expect(screen.getByText('Past due')).toBeInTheDocument();
    });

    it('applies destructive border for overdue status', () => {
      const { container } = render(
        <EventCard entry={{ ...mockEntry, status: 'overdue' }} siteId={1} />,
      );
      const card = container.firstChild;
      expect(card).toHaveClass('border-destructive/50');
    });
  });

  describe('Source Type Badges', () => {
    it('renders Freshness badge for freshness_recommendation source', () => {
      render(
        <EventCard entry={{ ...mockEntry, source_type: 'freshness_recommendation' }} siteId={1} />,
      );
      expect(screen.getByText('Freshness')).toBeInTheDocument();
    });

    it('renders Topic Gap badge for topic_gap_suggestion source', () => {
      render(
        <EventCard entry={{ ...mockEntry, source_type: 'topic_gap_suggestion' }} siteId={1} />,
      );
      expect(screen.getByText('Topic Gap')).toBeInTheDocument();
    });

    it('renders Analysis badge for analysis_run source', () => {
      render(<EventCard entry={{ ...mockEntry, source_type: 'analysis_run' }} siteId={1} />);
      expect(screen.getByText('Analysis')).toBeInTheDocument();
    });

    it('renders WordPress badge for wp_post source', () => {
      render(<EventCard entry={{ ...mockEntry, source_type: 'wp_post' }} siteId={1} />);
      expect(screen.getByText('WordPress')).toBeInTheDocument();
    });

    it('renders Manual badge for null source_type', () => {
      render(<EventCard entry={{ ...mockEntry, source_type: null }} siteId={1} />);
      expect(screen.getByText('Manual')).toBeInTheDocument();
    });

    it('renders fallback badge for unknown source type', () => {
      render(<EventCard entry={{ ...mockEntry, source_type: 'custom_source' }} siteId={1} />);
      expect(screen.getByText('custom source')).toBeInTheDocument();
    });
  });

  describe('Selection', () => {
    it('renders checkbox when onToggleSelection is provided', () => {
      const onToggleSelection = vi.fn();
      render(<EventCard entry={mockEntry} siteId={1} onToggleSelection={onToggleSelection} />);
      expect(screen.getByRole('checkbox')).toBeInTheDocument();
    });

    it('does not render checkbox when onToggleSelection is not provided', () => {
      render(<EventCard entry={mockEntry} siteId={1} />);
      expect(screen.queryByRole('checkbox')).not.toBeInTheDocument();
    });

    it('checkbox is checked when selected is true', () => {
      const onToggleSelection = vi.fn();
      render(
        <EventCard
          entry={mockEntry}
          siteId={1}
          selected={true}
          onToggleSelection={onToggleSelection}
        />,
      );
      expect(screen.getByRole('checkbox')).toBeChecked();
    });

    it('checkbox is unchecked when selected is false', () => {
      const onToggleSelection = vi.fn();
      render(
        <EventCard
          entry={mockEntry}
          siteId={1}
          selected={false}
          onToggleSelection={onToggleSelection}
        />,
      );
      expect(screen.getByRole('checkbox')).not.toBeChecked();
    });

    it('calls onToggleSelection when checkbox is clicked', () => {
      const onToggleSelection = vi.fn();
      render(<EventCard entry={mockEntry} siteId={1} onToggleSelection={onToggleSelection} />);
      fireEvent.click(screen.getByRole('checkbox'));
      expect(onToggleSelection).toHaveBeenCalledTimes(1);
    });
  });

  describe('Actions', () => {
    it('renders Mark Complete button for non-completed entries', () => {
      const onStatusChange = vi.fn();
      render(
        <EventCard
          entry={{ ...mockEntry, status: 'planned' }}
          siteId={1}
          onStatusChange={onStatusChange}
        />,
      );
      expect(screen.getByText('Mark Complete')).toBeInTheDocument();
    });

    it('does not render Mark Complete button for completed entries', () => {
      const onStatusChange = vi.fn();
      render(
        <EventCard
          entry={{ ...mockEntry, status: 'completed' }}
          siteId={1}
          onStatusChange={onStatusChange}
        />,
      );
      expect(screen.queryByText('Mark Complete')).not.toBeInTheDocument();
    });

    it('calls onStatusChange with completed status when Mark Complete is clicked', () => {
      const onStatusChange = vi.fn();
      render(<EventCard entry={mockEntry} siteId={1} onStatusChange={onStatusChange} />);
      fireEvent.click(screen.getByText('Mark Complete'));
      expect(onStatusChange).toHaveBeenCalledWith(mockEntry, 'completed');
    });

    it('renders Edit button when onEdit is provided', () => {
      const onEdit = vi.fn();
      render(<EventCard entry={mockEntry} siteId={1} onEdit={onEdit} />);
      expect(screen.getByText('Edit')).toBeInTheDocument();
    });

    it('does not render Edit button when onEdit is not provided', () => {
      render(<EventCard entry={mockEntry} siteId={1} />);
      expect(screen.queryByText('Edit')).not.toBeInTheDocument();
    });

    it('calls onEdit when Edit button is clicked', () => {
      const onEdit = vi.fn();
      render(<EventCard entry={mockEntry} siteId={1} onEdit={onEdit} />);
      fireEvent.click(screen.getByText('Edit'));
      expect(onEdit).toHaveBeenCalledWith(mockEntry);
    });
  });

  describe('Expandable Details', () => {
    it('details are collapsed by default', () => {
      render(<EventCard entry={mockEntry} siteId={1} />);
      const detailsButton = screen.getByText('View details');
      expect(detailsButton).toHaveAttribute('aria-expanded', 'false');
    });

    it('expands details when View details button is clicked', () => {
      render(<EventCard entry={mockEntry} siteId={1} />);
      const detailsButton = screen.getByText('View details');
      fireEvent.click(detailsButton);
      expect(detailsButton).toHaveAttribute('aria-expanded', 'true');
    });

    it('collapses details when View details button is clicked again', () => {
      render(<EventCard entry={mockEntry} siteId={1} />);
      const detailsButton = screen.getByText('View details');
      fireEvent.click(detailsButton);
      fireEvent.click(detailsButton);
      expect(detailsButton).toHaveAttribute('aria-expanded', 'false');
    });

    it('shows due date in details when expanded', () => {
      render(<EventCard entry={mockEntry} siteId={1} />);
      fireEvent.click(screen.getByText('View details'));
      expect(screen.getByText('Due Date:')).toBeInTheDocument();
    });

    it('shows scheduled date in details when expanded and scheduled_date exists', () => {
      render(<EventCard entry={mockEntry} siteId={1} />);
      fireEvent.click(screen.getByText('View details'));
      expect(screen.getByText('Scheduled:')).toBeInTheDocument();
    });

    it('does not show scheduled date when scheduled_date is null', () => {
      const entryWithoutScheduled = { ...mockEntry, scheduled_date: null };
      render(<EventCard entry={entryWithoutScheduled} siteId={1} />);
      fireEvent.click(screen.getByText('View details'));
      expect(screen.queryByText('Scheduled:')).not.toBeInTheDocument();
    });

    it('shows source information in details when expanded', () => {
      render(<EventCard entry={mockEntry} siteId={1} />);
      fireEvent.click(screen.getByText('View details'));
      expect(screen.getByText('Source:')).toBeInTheDocument();
      expect(screen.getByText(/Freshness \(ID: 123\)/)).toBeInTheDocument();
    });

    it('does not show source when source_type is null', () => {
      const entryWithoutSource = { ...mockEntry, source_type: null, source_id: null };
      render(<EventCard entry={entryWithoutSource} siteId={1} />);
      fireEvent.click(screen.getByText('View details'));
      expect(screen.queryByText('Source:')).not.toBeInTheDocument();
    });

    it('shows metadata in details when metadata exists', () => {
      render(<EventCard entry={mockEntry} siteId={1} />);
      fireEvent.click(screen.getByText('View details'));
      expect(screen.getByText('Metadata:')).toBeInTheDocument();
      expect(screen.getByText(/"priority": "high"/)).toBeInTheDocument();
    });

    it('does not show metadata when metadata is null', () => {
      const entryWithoutMetadata = { ...mockEntry, metadata: null };
      render(<EventCard entry={entryWithoutMetadata} siteId={1} />);
      fireEvent.click(screen.getByText('View details'));
      expect(screen.queryByText('Metadata:')).not.toBeInTheDocument();
    });

    it('does not show metadata when metadata is empty', () => {
      const entryWithEmptyMetadata = { ...mockEntry, metadata: {} };
      render(<EventCard entry={entryWithEmptyMetadata} siteId={1} />);
      fireEvent.click(screen.getByText('View details'));
      expect(screen.queryByText('Metadata:')).not.toBeInTheDocument();
    });
  });

  describe('URL Truncation', () => {
    it('truncates long URLs', () => {
      const longUrl = 'https://example.com/' + 'a'.repeat(100);
      const entryWithLongUrl = { ...mockEntry, page_url: longUrl };
      render(<EventCard entry={entryWithLongUrl} siteId={1} />);
      const link = screen.getByRole('link');
      expect(link.textContent).toContain('...');
      expect(link.textContent?.length).toBeLessThan(longUrl.length);
    });

    it('does not truncate short URLs', () => {
      const shortUrl = 'https://example.com/short';
      const entryWithShortUrl = { ...mockEntry, page_url: shortUrl };
      render(<EventCard entry={entryWithShortUrl} siteId={1} />);
      const link = screen.getByRole('link');
      expect(link.textContent).not.toContain('...');
    });
  });

  describe('Accessibility', () => {
    it('has accessible checkbox label', () => {
      const onToggleSelection = vi.fn();
      render(<EventCard entry={mockEntry} siteId={1} onToggleSelection={onToggleSelection} />);
      const checkbox = screen.getByRole('checkbox');
      expect(checkbox).toHaveAttribute('aria-label', 'Select task: Update homepage content');
    });

    it('details button has aria-controls', () => {
      render(<EventCard entry={mockEntry} siteId={1} />);
      const detailsButton = screen.getByText('View details');
      expect(detailsButton).toHaveAttribute('aria-controls', 'details-1');
    });
  });

  describe('Delete', () => {
    it('renders a delete button with accessible label', () => {
      render(<EventCard entry={mockEntry} siteId={1} />);
      expect(screen.getByRole('button', { name: /delete entry/i })).toBeInTheDocument();
    });

    it('shows a confirmation dialog when delete button is clicked', async () => {
      const { getByRole } = render(<EventCard entry={mockEntry} siteId={1} />);
      fireEvent.click(getByRole('button', { name: /delete entry/i }));
      expect(screen.getByRole('alertdialog')).toBeInTheDocument();
    });

    it('confirmation dialog contains expected text', async () => {
      render(<EventCard entry={mockEntry} siteId={1} />);
      fireEvent.click(screen.getByRole('button', { name: /delete entry/i }));
      expect(screen.getByText(/delete this calendar entry/i)).toBeInTheDocument();
      expect(screen.getByText(/this action cannot be undone/i)).toBeInTheDocument();
    });
  });
});
