// Copyright 2015-2025, University of Colorado Boulder

/**
 * CreditsNode displays the credits section in the About dialog.
 * See documentation below for conventions related to each credits field.
 *
 * @author Sam Reid (PhET Interactive Simulations)
 * @author Chris Malley (PixelZoom, Inc.)
 * @author Jonathan Olson <jonathan.olson@colorado.edu>
 */

import { string_joist_credits_title_StringProperty } from './strings/credits/title.js';
import { string_joist_credits_leadDesign_StringProperty } from './strings/credits/leadDesign.js';
import { string_joist_credits_softwareDevelopment_StringProperty } from './strings/credits/softwareDevelopment.js';
import { string_joist_credits_team_StringProperty } from './strings/credits/team.js';
import { string_joist_credits_contributors_StringProperty } from './strings/credits/contributors.js';
import { string_joist_credits_qualityAssurance_StringProperty } from './strings/credits/qualityAssurance.js';
import { string_joist_credits_graphicArts_StringProperty } from './strings/credits/graphicArts.js';
import { string_joist_credits_soundDesign_StringProperty } from './strings/credits/soundDesign.js';
import { string_joist_credits_thanks_StringProperty } from './strings/credits/thanks.js';
import '../../globals.js';
import { assert } from '../../scenerystack/assert.js';
import DerivedProperty from '../../axon/js/DerivedProperty.js';
import type TReadOnlyProperty from '../../axon/js/TReadOnlyProperty.js';
import optionize from '../../phet-core/js/optionize.js';
import StringUtils from '../../phetcommon/js/util/StringUtils.js';
import PhetFont from '../../scenery-phet/js/PhetFont.js';
import VoicingRichText from '../../scenery/js/accessibility/voicing/nodes/VoicingRichText.js';
import VoicingText from '../../scenery/js/accessibility/voicing/nodes/VoicingText.js';
import VBox, { type VBoxOptions } from '../../scenery/js/layout/nodes/VBox.js';
import type Node from '../../scenery/js/nodes/Node.js';
import VStrut from '../../scenery/js/nodes/VStrut.js';
import joist from './joist.js';

type SelfOptions = {
  titleFont?: PhetFont;
  textFont?: PhetFont;
};
type CreditsNodeOptions = SelfOptions & VBoxOptions;

export type CreditsData = {
  leadDesign?: string;
  softwareDevelopment?: string;
  team?: string;
  contributors?: string;
  qualityAssurance?: string;
  graphicArts?: string;
  soundDesign?: string;
  thanks?: string;
};

export default class CreditsNode extends VBox {
  private readonly disposeCreditsNode: () => void;

  public constructor( credits: CreditsData, options: CreditsNodeOptions ) {

    options = optionize<CreditsNodeOptions, SelfOptions, VBoxOptions>()( {
      titleFont: new PhetFont( { size: 18, weight: 'bold' } ),
      textFont: new PhetFont( 16 ),
      align: 'left',
      spacing: 1,
      maxWidth: 550
    }, options );

    const richTextOptions = {
      font: options.textFont,
      align: 'left' as const,
      lineWrap: options.maxWidth,
      tagName: 'p'
    };

    const children: Node[] = [];

    // Credits
    children.push( new VoicingText( string_joist_credits_title_StringProperty, {
      font: options.titleFont,

      // pdom
      readingBlockDisabledTagName: 'h2'
    } ) );

    const formatStringProperty = ( stringProperty: TReadOnlyProperty<string>, innerString: string ): TReadOnlyProperty<string> => {
      return new DerivedProperty( [ stringProperty ], string => {
        return StringUtils.format( string, `\u202a${innerString}\u202c` );
      } );
    };

    // Primary HTML5 designer first, followed by contributing designers (HTML5 and legacy) in alphabetical order.
    if ( credits.leadDesign ) {
      const designStringProperty = formatStringProperty( string_joist_credits_leadDesign_StringProperty, credits.leadDesign );
      children.push( new VoicingRichText( designStringProperty, richTextOptions ) );
    }

    // Primary HTML5 developer first, followed by contributing developers (HTML5 and legacy) in alphabetical order.
    if ( credits.softwareDevelopment ) {
      const developmentStringProperty = formatStringProperty( string_joist_credits_softwareDevelopment_StringProperty, credits.softwareDevelopment );
      children.push( new VoicingRichText( developmentStringProperty, richTextOptions ) );
    }

    // In alphabetical order (includes HTML5 and legacy team members)
    if ( credits.team ) {
      const teamStringProperty = formatStringProperty( string_joist_credits_team_StringProperty, credits.team );
      children.push( new VoicingRichText( teamStringProperty, richTextOptions ) );
    }

    // In alphabetical order (this field is new for HTML5 sims)
    if ( credits.contributors ) {
      const contributorsStringProperty = formatStringProperty( string_joist_credits_contributors_StringProperty, credits.contributors );
      children.push( new VoicingRichText( contributorsStringProperty, richTextOptions ) );
    }

    // In alphabetical order (this field is new for HTML5 sims)
    if ( credits.qualityAssurance ) {
      const qualityAssuranceStringProperty = formatStringProperty( string_joist_credits_qualityAssurance_StringProperty, credits.qualityAssurance );
      children.push( new VoicingRichText( qualityAssuranceStringProperty, richTextOptions ) );
    }

    // In alphabetical order (this field is new for HTML5 sims)
    if ( credits.graphicArts ) {
      const graphicArtsStringProperty = formatStringProperty( string_joist_credits_graphicArts_StringProperty, credits.graphicArts );
      children.push( new VoicingRichText( graphicArtsStringProperty, richTextOptions ) );
    }

    // In alphabetical order (this field is new for HTML5 sims)
    if ( credits.soundDesign ) {
      const soundDesignStringProperty = formatStringProperty( string_joist_credits_soundDesign_StringProperty, credits.soundDesign );
      children.push( new VoicingRichText( soundDesignStringProperty, richTextOptions ) );
    }

    // Thanks
    if ( credits.thanks ) {
      if ( children.length > 0 ) { children.push( new VStrut( 13 ) ); }
      children.push( new VoicingText( string_joist_credits_thanks_StringProperty, {
        font: options.titleFont,
        readingBlockDisabledTagName: 'h2'
      } ) );

      const thanksText = new VoicingRichText( credits.thanks, richTextOptions );
      children.push( thanksText );
    }

    assert && assert( !options.children, 'CreditsNode sets children' );
    options.children = children;

    super( options );

    this.disposeCreditsNode = () => {
      children.forEach( child => {
        child.dispose && child.dispose();
      } );
    };
  }

  public override dispose(): void {
    this.disposeCreditsNode();
    super.dispose();
  }
}

joist.register( 'CreditsNode', CreditsNode );