/**
 * Property-Based Tests: Vendor Issue Type Dropdown
 *
 * Feature: vendor-issue-type-dropdown
 *
 * Tests the pure determination logic that decides which issue type list
 * to display based on the project key input.
 *
 * Validates: Requirements 1.2, 1.3, 1.4, 1.5, 2.1, 2.3, 3.4, 3.5, 4.1, 4.2, 6.3
 */

const fc = require('fast-check');

// ---------------------------------------------------------------------------
// Replicate the pure functions from JiraPage.js for testing
// ---------------------------------------------------------------------------

const VENDOR_PROJECT_KEYS = [
  'AA_ADTRAN',
  'AA_ADVA',
  'AA_CASA',
  'AA_CISCO',
  'AACOMMSCOP',
  'AA_COMMSCOP',
  'AA_HARMONI',
  'AA_JUNIPER',
  'AA_VECIMA',
  'AA_VIAVI',
];

const VENDOR_ISSUE_TYPES = [
  'Epic',
  'Story',
  'Task',
  'Defect',
  'Production Defect/Incident Fix',
  'New Feature',
  'Spike',
  'Release Candidate',
  'Documentation',
];

const STEAM_ISSUE_TYPES = [
  'Story',
  'Epic',
  'Program',
  'Project',
  'Reservation',
  'Automation Maintenance',
];

function isVendorProject(projectKey, vendorKeys) {
  if (!projectKey || typeof projectKey !== 'string') return false;
  const normalized = projectKey.trim().toUpperCase();
  if (normalized.length === 0) return false;
  return vendorKeys.includes(normalized);
}

function getIssueTypesForProject(projectKey, vendorKeys, vendorTypes, steamTypes) {
  return isVendorProject(projectKey, vendorKeys) ? vendorTypes : steamTypes;
}

/**
 * Simulates the project_key onChange logic: resets issue_type only on context switch.
 */
function simulateProjectKeyChange(oldKey, newKey, currentIssueType, vendorKeys) {
  const wasVendor = isVendorProject(oldKey, vendorKeys);
  const isNowVendor = isVendorProject(newKey, vendorKeys);
  return (wasVendor !== isNowVendor) ? '' : currentIssueType;
}

// Helper: generate a vendor key with random casing and optional whitespace
const arbVendorKey = fc.constantFrom(...VENDOR_PROJECT_KEYS).chain(key =>
  fc.oneof(
    fc.constant(key),
    fc.constant(key.toLowerCase()),
    fc.constant(`  ${key}  `),
  )
);

// Helper: generate a string that does NOT match any vendor key after normalization
const arbNonVendorKey = fc.string({ minLength: 0, maxLength: 50 }).filter(s => {
  const normalized = s.trim().toUpperCase();
  return !VENDOR_PROJECT_KEYS.includes(normalized);
});

const arbNonVendorKeyNonEmpty = fc.string({ minLength: 1, maxLength: 30 }).filter(s => {
  const normalized = s.trim().toUpperCase();
  return !VENDOR_PROJECT_KEYS.includes(normalized) && normalized.length > 0;
});

// ---------------------------------------------------------------------------
// Property 1: Issue type list determination
// ---------------------------------------------------------------------------
describe('Feature: vendor-issue-type-dropdown, Property 1: Issue type list determination', () => {
  it('returns VENDOR_ISSUE_TYPES when project key matches a vendor key (case-insensitive, trimmed)', () => {
    fc.assert(
      fc.property(arbVendorKey, (key) => {
        const result = getIssueTypesForProject(key, VENDOR_PROJECT_KEYS, VENDOR_ISSUE_TYPES, STEAM_ISSUE_TYPES);
        expect(result).toBe(VENDOR_ISSUE_TYPES);
      }),
      { numRuns: 100 }
    );
  });

  it('returns STEAM_ISSUE_TYPES for any string that does not match a vendor key after normalization', () => {
    fc.assert(
      fc.property(arbNonVendorKey, (key) => {
        const result = getIssueTypesForProject(key, VENDOR_PROJECT_KEYS, VENDOR_ISSUE_TYPES, STEAM_ISSUE_TYPES);
        expect(result).toBe(STEAM_ISSUE_TYPES);
      }),
      { numRuns: 100 }
    );
  });

  it('returns STEAM_ISSUE_TYPES for null, undefined, and empty string', () => {
    const emptyInputs = fc.oneof(
      fc.constant(null),
      fc.constant(undefined),
      fc.constant(''),
      fc.constant('   '),
    );

    fc.assert(
      fc.property(emptyInputs, (key) => {
        const result = getIssueTypesForProject(key, VENDOR_PROJECT_KEYS, VENDOR_ISSUE_TYPES, STEAM_ISSUE_TYPES);
        expect(result).toBe(STEAM_ISSUE_TYPES);
      }),
      { numRuns: 100 }
    );
  });
});

// ---------------------------------------------------------------------------
// Property 2: Context switch resets issue type selection
// ---------------------------------------------------------------------------
describe('Feature: vendor-issue-type-dropdown, Property 2: Context switch resets issue type', () => {
  it('resets issue_type to empty when switching from vendor to non-vendor context', () => {
    const anyIssueType = fc.string({ minLength: 1, maxLength: 50 });

    fc.assert(
      fc.property(arbVendorKey, arbNonVendorKeyNonEmpty, anyIssueType, (oldKey, newKey, issueType) => {
        const result = simulateProjectKeyChange(oldKey, newKey, issueType, VENDOR_PROJECT_KEYS);
        expect(result).toBe('');
      }),
      { numRuns: 100 }
    );
  });

  it('resets issue_type to empty when switching from non-vendor to vendor context', () => {
    const anyIssueType = fc.string({ minLength: 1, maxLength: 50 });

    fc.assert(
      fc.property(arbNonVendorKeyNonEmpty, arbVendorKey, anyIssueType, (oldKey, newKey, issueType) => {
        const result = simulateProjectKeyChange(oldKey, newKey, issueType, VENDOR_PROJECT_KEYS);
        expect(result).toBe('');
      }),
      { numRuns: 100 }
    );
  });
});

// ---------------------------------------------------------------------------
// Property 3: Same context preserves issue type selection
// ---------------------------------------------------------------------------
describe('Feature: vendor-issue-type-dropdown, Property 3: Same context preserves issue type', () => {
  it('preserves issue_type when both old and new keys resolve to STEAM context', () => {
    const anyIssueType = fc.string({ minLength: 0, maxLength: 50 });

    fc.assert(
      fc.property(arbNonVendorKey, arbNonVendorKey, anyIssueType, (oldKey, newKey, issueType) => {
        const result = simulateProjectKeyChange(oldKey, newKey, issueType, VENDOR_PROJECT_KEYS);
        expect(result).toBe(issueType);
      }),
      { numRuns: 100 }
    );
  });

  it('preserves issue_type when both old and new keys resolve to vendor context', () => {
    const anyIssueType = fc.string({ minLength: 0, maxLength: 50 });

    fc.assert(
      fc.property(arbVendorKey, arbVendorKey, anyIssueType, (oldKey, newKey, issueType) => {
        const result = simulateProjectKeyChange(oldKey, newKey, issueType, VENDOR_PROJECT_KEYS);
        expect(result).toBe(issueType);
      }),
      { numRuns: 100 }
    );
  });
});
