import produce from "immer";
import { PID } from "@tingwujs/core";
import { SphereContext, SphereController } from "../../base";
import { AgendaSummaryStates, getAgendaSummaryInitState, Summary } from "./agendaSummaryState";
import { isOverOneHour } from "@tingwujs/common";

export interface AgendaSummaryEvents {
  rateSummary: {
    summary: Summary;
    star: number;
    onFinish: (summary: Partial<Summary>) => void;
  };
}

export class AgendaSummaryController extends SphereController<
  AgendaSummaryStates,
  AgendaSummaryEvents
> {
  key = "agendaSummary";

  constructor(context: SphereContext) {
    super(context, getAgendaSummaryInitState());
    this.updateUnitTime();
    this.listen();
  }

  listen() {
    const { tingwuController } = this.context;
    tingwuController.on("bookParagraphChangeSpecific", this.updateParagraphSummary);
    tingwuController.on("modelValueChange", this.updateParagraphSummary);
    tingwuController.on("agendasChange", this.updateUnitTime);
  }

  unlisten() {
    const { tingwuController } = this.context;
    tingwuController.off("bookParagraphChangeSpecific", this.updateParagraphSummary);
    tingwuController.off("modelValueChange", this.updateParagraphSummary);
    tingwuController.off("agendasChange", this.updateUnitTime);
  }

  getSummaries() {
    return this.getState("summaries");
  }

  setSummaries(summaries: Summary[]) {
    this.setState("summaries", summaries);
    this.updateParagraphSummary();
  }

  getSummariesByPid(pid: PID) {
    const pidSummariesMap = this.getState("pidSummariesMap");
    return pidSummariesMap[pid] || [];
  }

  updateUnitTime = () => {
    const { tingwuController } = this.context;
    const agendas = tingwuController.getAgendas();

    if (agendas.length === 0) {
      return;
    }

    let isThreeUnitTime = false;
    agendas.some(agenda => {
      if (isOverOneHour(agenda.beginTime)) {
        isThreeUnitTime = true;
        return true;
      }
      return false;
    });
    this.setState("isThreeUnitTime", isThreeUnitTime);
  };

  updateParagraphSummary = () => {
    const { tingwuController } = this.context;
    const paragraphs = tingwuController.getParagraphs();
    const summaries = this.getState("summaries");

    let isThreeUnitTime = false;

    if (paragraphs.length === 0 || summaries.length === 0) {
      this.setState("pidSummariesMap", {});
      this.setState("isThreeUnitTime", isThreeUnitTime);
      return;
    }

    const lastSummaries = summaries.slice();

    const pidSummariesMap: Record<PID, Summary[]> = {};

    paragraphs.some(paragraph => {
      const { pid, wids } = paragraph;
      const firstWid = wids[0];
      const lastWid = wids[wids.length - 1];
      const firstWord = tingwuController.getWord(firstWid);
      const lastWord = tingwuController.getWord(lastWid);

      if (!firstWord || !lastWord) {
        return false;
      }

      while (true) {
        if (lastSummaries.length === 0) {
          return true;
        }
        const summary = lastSummaries[0];
        if (isOverOneHour(summary.beginTime)) {
          isThreeUnitTime = true;
        }
        if (
          (summary.beginTime >= firstWord.beginTime && summary.beginTime < lastWord.endTime) ||
          summary.beginTime <= firstWord.beginTime
        ) {
          if (!pidSummariesMap[pid]) {
            pidSummariesMap[pid] = [];
          }

          pidSummariesMap[pid].push(summary);
          lastSummaries.shift();
        } else {
          break;
        }
      }
      return false;
    });

    this.setState("pidSummariesMap", pidSummariesMap);
    this.setState("isThreeUnitTime", isThreeUnitTime);
  };

  isFirstSummary(id: string) {
    const summaries = this.getSummaries();
    return summaries[0]?.id === id;
  }

  isLastSummary(id: string) {
    const summaries = this.getSummaries();
    if (summaries.length === 0) {
      return false;
    }
    return summaries[summaries.length - 1]?.id === id;
  }

  rateSummary(summary: Summary, star: number) {
    const onFinish = (summaryAttrs: Partial<Summary>) => {
      this.setSummaries(
        produce(this.getSummaries(), draft => {
          draft.forEach(s => {
            if (s.id === summary.id) {
              Object.assign(s, { star }, summaryAttrs);
            }
          });
        })
      );
    };
    this.emit("rateSummary", {
      summary,
      star,
      onFinish,
    });
  }

  setReadonly(readonly: boolean) {
    this.setState("readonly", readonly);
  }

  getReadonly() {
    return this.getState("readonly");
  }

  getDisplayTimeWidth() {
    return this.getState("isThreeUnitTime") ? 68 : 45;
  }
}
