import type {
  CircleChild,
  CircleCompletion,
  CircleGoal,
  CircleJobSituation,
  LearningContent,
  LearningSequence,
  LearningUnit,
  LearningWagtailPage
} from '@/types';


function _createEmptyLearningUnit(parentLearningSequence: LearningSequence): LearningUnit {
  return {
    id: 0,
    title: '',
    slug: '',
    translation_key: '',
    type: 'learnpath.LearningUnit',
    learningContents: [],
    minutes: 0,
    parentLearningSequence: parentLearningSequence,
    children: [],
    last: true,
  };
}

export function parseLearningSequences (children: CircleChild[]): LearningSequence[] {
  let learningSequence:LearningSequence | undefined;
  let learningUnit:LearningUnit | undefined;
  let learningContent:LearningContent | undefined;
  let previousLearningContent: LearningContent | undefined;
  const result:LearningSequence[] = [];

  children.forEach((child) => {
    if (child.type === 'learnpath.LearningSequence') {
      if (learningSequence) {
        if (learningUnit) {
          learningUnit.last = true;
          learningSequence.learningUnits.push(learningUnit);
        }
        result.push(learningSequence);
      }
      learningSequence = Object.assign(child, {learningUnits: []});

      // initialize empty learning unit if there will not come a learning unit next
      learningUnit = _createEmptyLearningUnit(learningSequence);
    } else if (child.type === 'learnpath.LearningUnit') {
      if (!learningSequence) {
        throw new Error('LearningUnit found before LearningSequence');
      }

      if (learningUnit && learningUnit.learningContents.length) {
        learningSequence.learningUnits.push(learningUnit);
      }

      learningUnit = Object.assign(child, {
        learningContents: [],
        parentLearningSequence: learningSequence,
        children: child.children.map((c) => {
          c.parentLearningUnit = learningUnit;
          c.parentLearningSequence = learningSequence;
          return c;
        })
      });
    } else if (child.type === 'learnpath.LearningContent') {
      if (!learningUnit) {
        throw new Error('LearningContent found before LearningUnit');
      }
      previousLearningContent = learningContent;

      learningContent = Object.assign(child, {
        parentLearningSequence: learningSequence,
        parentLearningUnit: learningUnit,
        previousLearningContent: previousLearningContent,
      });

      if (previousLearningContent) {
        previousLearningContent.nextLearningContent = learningContent;
      }

      learningUnit.learningContents.push(child);
    }
  });

  if (learningUnit && learningSequence) {
    // TypeScript does not get it here...
    learningUnit.last = true;
    (learningSequence as LearningSequence).learningUnits.push(learningUnit);
    result.push(learningSequence);
  } else {
    throw new Error('Finished with LearningContent but there is no LearningSequence and LearningUnit');
  }

  // sum minutes
  result.forEach((learningSequence) => {
    learningSequence.minutes = 0;
    learningSequence.learningUnits.forEach((learningUnit) => {
      learningUnit.minutes = 0;
      learningUnit.learningContents.forEach((learningContent) => {
        learningUnit.minutes += learningContent.minutes;
      });
      learningSequence.minutes += learningUnit.minutes;
    });
  });

  return result;
}

export class Circle implements LearningWagtailPage {
  readonly type = 'learnpath.Circle';
  readonly learningSequences: LearningSequence[];
  readonly completed: boolean;

  constructor(
    public readonly id: number,
    public readonly slug: string,
    public readonly title: string,
    public readonly translation_key: string,
    public description: string,
    public children: CircleChild[],
    public goals: CircleGoal[],
    public job_situations: CircleJobSituation[],
  ) {
    this.learningSequences = parseLearningSequences(this.children);
    this.completed = false;
  }

  public static fromJson(json: any): Circle {
    // TODO add error checking when the data does not conform to the schema
    return new Circle(
      json.id,
      json.slug,
      json.title,
      json.translation_key,
      json.description,
      json.children,
      json.goals,
      json.job_situations,
    )
  }

  public get flatChildren(): CircleChild[] {
    const result: CircleChild[] = [];
    this.learningSequences.forEach((learningSequence) => {
      learningSequence.learningUnits.forEach((learningUnit) => {
        learningUnit.children.forEach((learningUnitQuestion) => {
          result.push(learningUnitQuestion);
        })
        learningUnit.learningContents.forEach((learningContent) => {
          result.push(learningContent);
        });
      });
    });
    return result;
  }

  public someFinishedInLearningSequence(translationKey: string): boolean {
    if (translationKey) {
      return this.flatChildren.filter((lc) => {
        return lc.completed && lc.parentLearningSequence?.translation_key === translationKey;
      }).length > 0;
    }

    return false;
  }

  public parseCompletionData(completionData: CircleCompletion[]) {
    this.flatChildren.forEach((page) => {
      const pageIndex = completionData.findIndex((e) => {
        return e.page_key === page.translation_key;
      });
      if (pageIndex >= 0) {
        page.completed = completionData[pageIndex].completed;
      } else {
        page.completed = undefined;
      }
    });
  }
}
