/**
 * The badge on cards, rows and the album title.
 *
 * The `partial` state was added so an album you hold nine tracks of
 * looks different from one you hold all twelve of. The risk it carries
 * is that a ring is a *claim about a total*, and most of an untagged
 * library has no total — so the rules under test are that the arc
 * reflects the real fraction, that extras do not overfill it, and that
 * the count reaches a screen reader rather than only an eye.
 */
import { describe, expect, it } from 'vitest';

import '@components/library-status-indicator/library-status-indicator';
import { fixture, shadow } from '@test/support/render';

/** The stroke-dashoffset the arc was drawn with, as a fraction filled. */
function filledFraction(el: Element): number {
  const arc = shadow(el, '.ring-fill');
  const dash = Number(arc?.getAttribute('stroke-dasharray'));
  const offset = Number(arc?.getAttribute('stroke-dashoffset'));

  return (dash - offset) / dash;
}

describe('the library status badge', () => {
  it('draws no ring unless it is partial', async () => {
    const el = await fixture('library-status-indicator', {
      status: 'in-library',
    });

    expect(shadow(el, '.ring-fill')).toBeNull();
    expect(shadow(el, 'wa-icon')?.getAttribute('name')).toBe('check');
  });

  it('fills the arc to the held fraction', async () => {
    const el = await fixture('library-status-indicator', {
      status: 'partial',
      owned: 9,
      expected: 12,
    });

    expect(filledFraction(el)).toBeCloseTo(0.75, 5);
  });

  it('does not overfill on bonus tracks', async () => {
    const el = await fixture('library-status-indicator', {
      status: 'partial',
      owned: 13,
      expected: 12,
    });

    expect(filledFraction(el)).toBeCloseTo(1, 5);
  });

  it('does not divide by a total it was never given', async () => {
    const el = await fixture('library-status-indicator', {
      status: 'partial',
      owned: 3,
      expected: 0,
    });

    expect(filledFraction(el)).toBe(0);
  });

  it('says the count, not just the shape', async () => {
    const el = await fixture('library-status-indicator', {
      status: 'partial',
      owned: 9,
      expected: 12,
      entityType: 'album',
      label: 'Glass Harbour',
    });

    const name = shadow(el, '.badge')?.getAttribute('aria-label') ?? '';

    expect(name).toContain('9 of 12');
    expect(name).toContain('Glass Harbour');
  });
});

/**
 * A partly-held album is the one state that is *actionable and
 * counted*: there are tracks left to ask for, so the badge is a button
 * — and a control is named after what activating it does, which is how
 * the count came to be dropped from exactly the state the ring exists
 * for. Both, or the ring says "some" to an eye and nothing to anyone
 * else.
 */
describe('a partial badge that can act', () => {
  it('names the action and keeps the count', async () => {
    const el = await fixture('library-status-indicator', {
      status: 'partial',
      owned: 9,
      expected: 12,
      entityType: 'album',
      label: 'Glass Harbour',
      requestMbid: 'rg-1',
    });

    const name = shadow(el, '.badge')?.getAttribute('aria-label') ?? '';

    expect(shadow(el, 'button.badge')).not.toBeNull();
    expect(name).toContain('Request the rest of');
    expect(name).toContain('9 of 12');
  });
});
