import React from 'react';
import { render, fireEvent, waitFor } from '@testing-library/react-native';
import { Alert } from 'react-native';
import BeneficiaryDetailScreen from '@/app/(tabs)/beneficiaries/[id]/index';
import { api } from '@/services/api';
import { router, useLocalSearchParams } from 'expo-router';

// Mock dependencies
jest.mock('expo-router', () => ({
  router: {
    replace: jest.fn(),
    push: jest.fn(),
    setParams: jest.fn(),
  },
  useLocalSearchParams: jest.fn(),
}));

jest.mock('@/services/api');
jest.mock('@/contexts/BeneficiaryContext', () => ({
  useBeneficiary: () => ({
    setCurrentBeneficiary: jest.fn(),
  }),
}));

jest.mock('@/components/ui/Toast', () => ({
  useToast: () => ({
    success: jest.fn(),
    error: jest.fn(),
    info: jest.fn(),
  }),
}));

jest.mock('react-native/Libraries/Alert/Alert', () => ({
  alert: jest.fn(),
}));

describe('BeneficiaryDetailScreen - Role-based Edit Modal', () => {
  const mockBeneficiaryCustodian = {
    id: 1,
    name: 'John Doe',
    displayName: 'John Doe',
    address: '123 Main St',
    avatar: 'https://example.com/avatar.jpg',
    role: 'custodian',
    customName: null,
    status: 'online',
    subscription: { status: 'active' },
    devices: [{ id: '1', type: 'motion', name: 'Sensor 1', status: 'online' }],
    equipmentStatus: 'active',
  };

  const mockBeneficiaryCaretaker = {
    ...mockBeneficiaryCustodian,
    role: 'caretaker',
    customName: 'Dad',
  };

  const mockBeneficiaryGuardian = {
    ...mockBeneficiaryCustodian,
    role: 'guardian',
    customName: 'Grandpa',
  };

  beforeEach(() => {
    jest.clearAllMocks();
    (useLocalSearchParams as jest.Mock).mockReturnValue({ id: '1' });
    (api.getLegacyWebViewCredentials as jest.Mock).mockResolvedValue({
      token: 'test-token',
      userName: 'test-user',
      userId: '1',
    });
    (api.isLegacyTokenExpiringSoon as jest.Mock).mockResolvedValue(false);
  });

  describe('Custodian Edit Modal', () => {
    beforeEach(() => {
      (api.getWellNuoBeneficiary as jest.Mock).mockResolvedValue({
        ok: true,
        data: mockBeneficiaryCustodian,
      });
    });

    it('shows full edit form for custodian (name, address, avatar)', async () => {
      const { getByText, getByPlaceholderText } = render(<BeneficiaryDetailScreen />);

      // Wait for data to load
      await waitFor(() => {
        expect(getByText('John Doe')).toBeTruthy();
      });

      // Open menu and click Edit
      const menuButton = getByText('☰'); // Adjust based on actual icon
      fireEvent.press(menuButton);

      const editButton = getByText('Edit');
      fireEvent.press(editButton);

      // Should show custodian edit form
      await waitFor(() => {
        expect(getByText('Edit Profile')).toBeTruthy();
        expect(getByPlaceholderText('Full name')).toBeTruthy();
        expect(getByPlaceholderText('Street address')).toBeTruthy();
        // Avatar picker should be visible
      });

      // Should NOT show nickname field
      expect(() => getByPlaceholderText('e.g., "Mom", "Dad", "Grandma"')).toThrow();
    });

    it('allows custodian to update name and address', async () => {
      (api.updateWellNuoBeneficiary as jest.Mock).mockResolvedValue({ ok: true });

      const { getByText, getByPlaceholderText, getByTestId } = render(<BeneficiaryDetailScreen />);

      await waitFor(() => {
        expect(getByText('John Doe')).toBeTruthy();
      });

      // Open edit modal
      fireEvent.press(getByTestId('menu-button'));
      fireEvent.press(getByText('Edit'));

      // Update name
      const nameInput = getByPlaceholderText('Full name');
      fireEvent.changeText(nameInput, 'Jane Doe');

      // Update address
      const addressInput = getByPlaceholderText('Street address');
      fireEvent.changeText(addressInput, '456 Oak Ave');

      // Save
      const saveButton = getByText('Save');
      fireEvent.press(saveButton);

      await waitFor(() => {
        expect(api.updateWellNuoBeneficiary).toHaveBeenCalledWith(1, {
          name: 'Jane Doe',
          address: '456 Oak Ave',
        });
      });
    });

    it('validates that name is required for custodian', async () => {
      const { getByText, getByPlaceholderText, getByTestId } = render(<BeneficiaryDetailScreen />);

      await waitFor(() => {
        expect(getByText('John Doe')).toBeTruthy();
      });

      // Open edit modal
      fireEvent.press(getByTestId('menu-button'));
      fireEvent.press(getByText('Edit'));

      // Clear name
      const nameInput = getByPlaceholderText('Full name');
      fireEvent.changeText(nameInput, '');

      // Try to save
      const saveButton = getByText('Save');
      fireEvent.press(saveButton);

      // Should show error (via toast)
      await waitFor(() => {
        expect(api.updateWellNuoBeneficiary).not.toHaveBeenCalled();
      });
    });
  });

  describe('Caretaker Edit Modal', () => {
    beforeEach(() => {
      (api.getWellNuoBeneficiary as jest.Mock).mockResolvedValue({
        ok: true,
        data: mockBeneficiaryCaretaker,
      });
    });

    it('shows only nickname field for caretaker', async () => {
      const { getByText, getByPlaceholderText, queryByPlaceholderText } = render(
        <BeneficiaryDetailScreen />
      );

      await waitFor(() => {
        expect(getByText('John Doe')).toBeTruthy();
      });

      // Open edit modal
      fireEvent.press(getByText('Edit'));

      // Should show caretaker edit form
      await waitFor(() => {
        expect(getByText('Edit Nickname')).toBeTruthy();
        expect(getByPlaceholderText('e.g., "Mom", "Dad", "Grandma"')).toBeTruthy();
      });

      // Should NOT show full profile fields
      expect(queryByPlaceholderText('Full name')).toBeNull();
      expect(queryByPlaceholderText('Street address')).toBeNull();
    });

    it('shows original name as reference for caretaker', async () => {
      const { getByText } = render(<BeneficiaryDetailScreen />);

      await waitFor(() => {
        expect(getByText('John Doe')).toBeTruthy();
      });

      // Open edit modal
      fireEvent.press(getByText('Edit'));

      // Should show original name
      await waitFor(() => {
        expect(getByText('Original name:')).toBeTruthy();
        expect(getByText('John Doe')).toBeTruthy();
      });
    });

    it('allows caretaker to update nickname only', async () => {
      (api.updateBeneficiaryCustomName as jest.Mock).mockResolvedValue({ ok: true });

      const { getByText, getByPlaceholderText } = render(<BeneficiaryDetailScreen />);

      await waitFor(() => {
        expect(getByText('John Doe')).toBeTruthy();
      });

      // Open edit modal
      fireEvent.press(getByText('Edit'));

      // Update nickname
      const nicknameInput = getByPlaceholderText('e.g., "Mom", "Dad", "Grandma"');
      fireEvent.changeText(nicknameInput, 'Papa');

      // Save
      const saveButton = getByText('Save');
      fireEvent.press(saveButton);

      await waitFor(() => {
        expect(api.updateBeneficiaryCustomName).toHaveBeenCalledWith(1, 'Papa');
      });
    });

    it('allows caretaker to clear nickname', async () => {
      (api.updateBeneficiaryCustomName as jest.Mock).mockResolvedValue({ ok: true });

      const { getByText, getByPlaceholderText } = render(<BeneficiaryDetailScreen />);

      await waitFor(() => {
        expect(getByText('John Doe')).toBeTruthy();
      });

      // Open edit modal
      fireEvent.press(getByText('Edit'));

      // Clear nickname
      const nicknameInput = getByPlaceholderText('e.g., "Mom", "Dad", "Grandma"');
      fireEvent.changeText(nicknameInput, '');

      // Save
      const saveButton = getByText('Save');
      fireEvent.press(saveButton);

      await waitFor(() => {
        expect(api.updateBeneficiaryCustomName).toHaveBeenCalledWith(1, null);
      });
    });

    it('does NOT call updateWellNuoBeneficiary for caretaker', async () => {
      (api.updateBeneficiaryCustomName as jest.Mock).mockResolvedValue({ ok: true });

      const { getByText, getByPlaceholderText } = render(<BeneficiaryDetailScreen />);

      await waitFor(() => {
        expect(getByText('John Doe')).toBeTruthy();
      });

      // Open edit modal
      fireEvent.press(getByText('Edit'));

      // Update nickname
      const nicknameInput = getByPlaceholderText('e.g., "Mom", "Dad", "Grandma"');
      fireEvent.changeText(nicknameInput, 'Dad');

      // Save
      fireEvent.press(getByText('Save'));

      await waitFor(() => {
        expect(api.updateWellNuoBeneficiary).not.toHaveBeenCalled();
        expect(api.updateBeneficiaryCustomName).toHaveBeenCalled();
      });
    });
  });

  describe('Guardian Edit Modal', () => {
    beforeEach(() => {
      (api.getWellNuoBeneficiary as jest.Mock).mockResolvedValue({
        ok: true,
        data: mockBeneficiaryGuardian,
      });
    });

    it('shows only nickname field for guardian (same as caretaker)', async () => {
      const { getByText, getByPlaceholderText, queryByPlaceholderText } = render(
        <BeneficiaryDetailScreen />
      );

      await waitFor(() => {
        expect(getByText('John Doe')).toBeTruthy();
      });

      // Open edit modal
      fireEvent.press(getByText('Edit'));

      // Should show nickname form (same as caretaker)
      await waitFor(() => {
        expect(getByText('Edit Nickname')).toBeTruthy();
        expect(getByPlaceholderText('e.g., "Mom", "Dad", "Grandma"')).toBeTruthy();
      });

      // Should NOT show full profile fields
      expect(queryByPlaceholderText('Full name')).toBeNull();
      expect(queryByPlaceholderText('Street address')).toBeNull();
    });

    it('allows guardian to update nickname', async () => {
      (api.updateBeneficiaryCustomName as jest.Mock).mockResolvedValue({ ok: true });

      const { getByText, getByPlaceholderText } = render(<BeneficiaryDetailScreen />);

      await waitFor(() => {
        expect(getByText('John Doe')).toBeTruthy();
      });

      // Open edit modal
      fireEvent.press(getByText('Edit'));

      // Update nickname
      const nicknameInput = getByPlaceholderText('e.g., "Mom", "Dad", "Grandma"');
      fireEvent.changeText(nicknameInput, 'Gramps');

      // Save
      fireEvent.press(getByText('Save'));

      await waitFor(() => {
        expect(api.updateBeneficiaryCustomName).toHaveBeenCalledWith(1, 'Gramps');
      });
    });
  });

  describe('Edit Modal Behavior', () => {
    it('opens edit modal when navigated with edit=true param', async () => {
      (useLocalSearchParams as jest.Mock).mockReturnValue({ id: '1', edit: 'true' });
      (api.getWellNuoBeneficiary as jest.Mock).mockResolvedValue({
        ok: true,
        data: mockBeneficiaryCustodian,
      });

      const { getByText } = render(<BeneficiaryDetailScreen />);

      // Edit modal should open automatically
      await waitFor(() => {
        expect(getByText('Edit Profile')).toBeTruthy();
      });

      // Should clear the edit param
      expect(router.setParams).toHaveBeenCalledWith({ edit: undefined });
    });

    it('closes edit modal when Save completes successfully', async () => {
      (api.updateWellNuoBeneficiary as jest.Mock).mockResolvedValue({ ok: true });
      (api.getWellNuoBeneficiary as jest.Mock).mockResolvedValue({
        ok: true,
        data: mockBeneficiaryCustodian,
      });

      const { getByText, getByPlaceholderText, queryByText } = render(
        <BeneficiaryDetailScreen />
      );

      await waitFor(() => {
        expect(getByText('John Doe')).toBeTruthy();
      });

      // Open edit modal
      fireEvent.press(getByText('Edit'));

      // Update name
      const nameInput = getByPlaceholderText('Full name');
      fireEvent.changeText(nameInput, 'Jane Doe');

      // Save
      fireEvent.press(getByText('Save'));

      // Modal should close
      await waitFor(() => {
        expect(queryByText('Edit Profile')).toBeNull();
      });
    });

    it('reloads beneficiary data after successful save', async () => {
      (api.updateWellNuoBeneficiary as jest.Mock).mockResolvedValue({ ok: true });
      (api.getWellNuoBeneficiary as jest.Mock).mockResolvedValue({
        ok: true,
        data: mockBeneficiaryCustodian,
      });

      const { getByText, getByPlaceholderText } = render(<BeneficiaryDetailScreen />);

      await waitFor(() => {
        expect(getByText('John Doe')).toBeTruthy();
      });

      // Open and save edit
      fireEvent.press(getByText('Edit'));
      const nameInput = getByPlaceholderText('Full name');
      fireEvent.changeText(nameInput, 'Jane Doe');
      fireEvent.press(getByText('Save'));

      // Should reload beneficiary data
      await waitFor(() => {
        expect(api.getWellNuoBeneficiary).toHaveBeenCalledTimes(2); // Initial load + reload
      });
    });
  });
});
