import React from 'react';
import { render, screen } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
import { MyWorkspacePage } from '../index';
import * as useWorkspaceData from '../../../hooks/useWorkspaceData';
import * as UserProvider from '../../../providers/UserProvider';

// Mock CSS imports
vi.mock('../MyWorkspacePage.css', () => ({}));
vi.mock('../../../../styles/settings.css', () => ({}));

// Mock child components to test integration
vi.mock('../NotificationsSection', () => ({
  NotificationsSection: ({ notifications, loading }) => (
    <div data-testid="notifications-section">
      {loading ? 'Loading...' : `${notifications.length} notifications`}
    </div>
  ),
}));

vi.mock('../NeedsAttentionSection', () => ({
  NeedsAttentionSection: ({ loading }) => (
    <div data-testid="needs-attention-section">
      {loading ? 'Loading...' : 'Needs Attention'}
    </div>
  ),
}));

vi.mock('../MyNodesSection', () => ({
  MyNodesSection: ({ ownedNodes, loading }) => (
    <div data-testid="my-nodes-section">
      {loading ? 'Loading...' : `${ownedNodes.length} owned nodes`}
    </div>
  ),
}));

vi.mock('../MaterializationsSection', () => ({
  MaterializationsSection: ({ nodes, loading }) => (
    <div data-testid="materializations-section">
      {loading ? 'Loading...' : `${nodes.length} materializations`}
    </div>
  ),
}));

vi.mock('../ActiveBranchesSection', () => ({
  ActiveBranchesSection: ({ loading }) => (
    <div data-testid="active-branches-section">
      {loading ? 'Loading...' : 'Active Branches'}
    </div>
  ),
}));

describe('<MyWorkspacePage />', () => {
  const mockCurrentUser = {
    username: 'test.user@example.com',
    email: 'test.user@example.com',
  };

  const mockOwnedNodes = [
    {
      name: 'default.test_metric',
      type: 'METRIC',
      current: { displayName: 'Test Metric', updatedAt: '2024-01-01' },
    },
    {
      name: 'default.test_dimension',
      type: 'DIMENSION',
      current: { displayName: 'Test Dimension', updatedAt: '2024-01-02' },
    },
  ];

  const mockNotifications = [
    {
      entity_name: 'default.test_metric',
      entity_type: 'node',
      activity_type: 'update',
      created_at: '2024-01-01T00:00:00Z',
      user: 'test.user@example.com',
      node_type: 'metric',
      display_name: 'Test Metric',
    },
  ];

  const mockMaterializations = [
    {
      name: 'default.test_cube',
      type: 'CUBE',
      current: {
        displayName: 'Test Cube',
        availability: {
          validThroughTs: Date.now() - 1000 * 60 * 60, // 1 hour ago
        },
        materializations: [{ name: 'mat1', schedule: '@daily' }],
      },
    },
  ];

  const makeLoadingStates = (loading = false) => ({
    myNodes: loading,
    collections: loading,
    notifications: loading,
    materializations: loading,
    needsAttention: loading,
    namespace: loading,
  });

  const makeDashboardData = (overrides = {}) => ({
    data: {
      ownedNodes: [],
      ownedHasMore: {},
      recentlyEdited: [],
      editedHasMore: {},
      watchedNodes: [],
      notifications: [],
      materializedNodes: [],
      needsAttention: {
        nodesMissingDescription: [],
        invalidNodes: [],
        staleDrafts: [],
        orphanedDimensions: [],
      },
      hasPersonalNamespace: true,
      ...overrides,
    },
    loadingStates: makeLoadingStates(false),
  });

  beforeEach(() => {
    vi.clearAllMocks();
  });

  it('should render loading state', () => {
    vi.spyOn(UserProvider, 'useCurrentUser').mockReturnValue({
      currentUser: null,
      loading: true,
    });
    vi.spyOn(useWorkspaceData, 'useWorkspaceDashboardData').mockReturnValue(
      makeDashboardData(),
    );

    render(
      <MemoryRouter>
        <MyWorkspacePage />
      </MemoryRouter>,
    );

    expect(screen.getByText('Dashboard')).toBeInTheDocument();
    // Sections are not shown while user is loading
    expect(screen.queryByTestId('my-nodes-section')).not.toBeInTheDocument();
  });

  it('should render all sections when data is loaded', () => {
    vi.spyOn(UserProvider, 'useCurrentUser').mockReturnValue({
      currentUser: mockCurrentUser,
      loading: false,
    });
    vi.spyOn(useWorkspaceData, 'useWorkspaceDashboardData').mockReturnValue(
      makeDashboardData({
        ownedNodes: mockOwnedNodes,
        notifications: mockNotifications,
        materializedNodes: mockMaterializations,
      }),
    );

    render(
      <MemoryRouter>
        <MyWorkspacePage />
      </MemoryRouter>,
    );

    expect(screen.getByTestId('my-nodes-section')).toHaveTextContent(
      '2 owned nodes',
    );
    expect(screen.getByTestId('notifications-section')).toHaveTextContent(
      '1 notifications',
    );
    expect(screen.getByTestId('materializations-section')).toHaveTextContent(
      '1 materializations',
    );
    expect(screen.getByTestId('needs-attention-section')).toBeInTheDocument();
    expect(screen.getByTestId('active-branches-section')).toBeInTheDocument();
  });

  it('should pass correct props to sections', () => {
    vi.spyOn(UserProvider, 'useCurrentUser').mockReturnValue({
      currentUser: mockCurrentUser,
      loading: false,
    });
    vi.spyOn(useWorkspaceData, 'useWorkspaceDashboardData').mockReturnValue(
      makeDashboardData({ ownedNodes: mockOwnedNodes }),
    );

    render(
      <MemoryRouter>
        <MyWorkspacePage />
      </MemoryRouter>,
    );

    expect(screen.getByTestId('my-nodes-section')).toBeInTheDocument();
    expect(screen.getByTestId('notifications-section')).toBeInTheDocument();
    expect(screen.getByTestId('needs-attention-section')).toBeInTheDocument();
  });

  it('should filter out non-stale materializations from NeedsAttention', () => {
    const now = Date.now();
    const freshNode = {
      name: 'default.fresh_cube',
      type: 'CUBE',
      current: {
        availability: {
          validThroughTs: now - 1000 * 60 * 60 * 10, // 10 hours ago (< 72h, not stale)
        },
      },
    };

    vi.spyOn(UserProvider, 'useCurrentUser').mockReturnValue({
      currentUser: mockCurrentUser,
      loading: false,
    });
    vi.spyOn(useWorkspaceData, 'useWorkspaceDashboardData').mockReturnValue(
      makeDashboardData({ materializedNodes: [freshNode] }),
    );

    render(
      <MemoryRouter>
        <MyWorkspacePage />
      </MemoryRouter>,
    );

    // Page renders without crash — stale filter ran without errors
    expect(screen.getByTestId('materializations-section')).toHaveTextContent(
      '1 materializations',
    );
    expect(screen.getByTestId('needs-attention-section')).toBeInTheDocument();
  });

  it('should exclude nodes with null validThroughTs from stale list', () => {
    const pendingNode = {
      name: 'default.pending_cube',
      type: 'CUBE',
      current: {
        availability: {
          validThroughTs: null,
        },
      },
    };

    vi.spyOn(UserProvider, 'useCurrentUser').mockReturnValue({
      currentUser: mockCurrentUser,
      loading: false,
    });
    vi.spyOn(useWorkspaceData, 'useWorkspaceDashboardData').mockReturnValue(
      makeDashboardData({ materializedNodes: [pendingNode] }),
    );

    render(
      <MemoryRouter>
        <MyWorkspacePage />
      </MemoryRouter>,
    );

    // Pending node (null validThroughTs) should not be passed as stale
    expect(screen.getByTestId('needs-attention-section')).toBeInTheDocument();
  });

  it('should exclude nodes with no availability from stale list', () => {
    const noAvailabilityNode = {
      name: 'default.no_avail_cube',
      type: 'CUBE',
      current: {},
    };

    vi.spyOn(UserProvider, 'useCurrentUser').mockReturnValue({
      currentUser: mockCurrentUser,
      loading: false,
    });
    vi.spyOn(useWorkspaceData, 'useWorkspaceDashboardData').mockReturnValue(
      makeDashboardData({ materializedNodes: [noAvailabilityNode] }),
    );

    render(
      <MemoryRouter>
        <MyWorkspacePage />
      </MemoryRouter>,
    );

    expect(screen.getByTestId('needs-attention-section')).toBeInTheDocument();
  });

  it('should derive personal namespace from username', () => {
    vi.spyOn(UserProvider, 'useCurrentUser').mockReturnValue({
      currentUser: { username: 'jane.doe@company.com' },
      loading: false,
    });
    vi.spyOn(useWorkspaceData, 'useWorkspaceDashboardData').mockReturnValue(
      makeDashboardData(),
    );

    render(
      <MemoryRouter>
        <MyWorkspacePage />
      </MemoryRouter>,
    );

    // NeedsAttentionSection mock receives personalNamespace="users.jane.doe"
    expect(screen.getByTestId('needs-attention-section')).toBeInTheDocument();
  });

  it('should calculate stale materializations correctly', () => {
    const now = Date.now();
    const staleNode = {
      name: 'default.stale_cube',
      type: 'CUBE',
      current: {
        displayName: 'Stale Cube',
        availability: {
          validThroughTs: now - 1000 * 60 * 60 * 80, // 80 hours ago (> 72 hours)
        },
      },
    };

    vi.spyOn(UserProvider, 'useCurrentUser').mockReturnValue({
      currentUser: mockCurrentUser,
      loading: false,
    });
    vi.spyOn(useWorkspaceData, 'useWorkspaceDashboardData').mockReturnValue(
      makeDashboardData({ materializedNodes: [staleNode] }),
    );

    render(
      <MemoryRouter>
        <MyWorkspacePage />
      </MemoryRouter>,
    );

    // The stale materialization should be passed to NeedsAttentionSection
    expect(screen.getByTestId('needs-attention-section')).toBeInTheDocument();
  });
});
