import { Injectable, Logger } from '@nestjs/common';
import { RedmineTypes } from '../models/redmine-types';
import nano from 'nano';
import { Subject } from 'rxjs';
import { Issues } from '../couchdb-datasources/issues';
import { SaveResponse } from '../models/save-response';
import { Timestamped } from '../models/timestamped';
import { TimestampNowFill } from '../utils/timestamp-now-fill';

@Injectable()
export class RedmineIssuesCacheWriterService {
  private logger = new Logger(RedmineIssuesCacheWriterService.name);

  subject = new Subject<SaveResponse>();

  constructor(private issues: Issues) {}

  async saveIssue(issue: RedmineTypes.Issue): Promise<SaveResponse> {
    this.logger.debug(
      `Saving issue ${issue?.id || '-'} (${issue?.subject || '-'})`,
    );
    const id = Number(issue['id']);
    let prevIssue: (nano.DocumentGetResponse & RedmineTypes.Issue) | null;
    const issueDb = await this.issues.getDatasource();
    if (!issueDb) {
      throw `CouchDb datasource must defined`;
    }
    try {
      prevIssue = await issueDb.get(String(id));
    } catch (ex) {
      prevIssue = null;
    }
    const newIssue: nano.DocumentGetResponse &
      RedmineTypes.Issue &
      Timestamped = TimestampNowFill({ ...(issue as any) });
    newIssue._id = String(id);
    if (prevIssue) {
      newIssue._rev = prevIssue._rev;
    }
    await issueDb.insert(newIssue);
    const res = {
      prev: prevIssue,
      current: newIssue,
      journalsDiff: this.getJournalsDiff(prevIssue, newIssue),
    };
    this.logger.debug(
      `Saving issue success #${issue?.id || '-'} - ${issue?.subject || '-'}`,
    );
    this.subject.next(res);
    return res;
  }

  getJournalsDiff(
    prev: (nano.DocumentGetResponse & RedmineTypes.Issue) | null,
    current: nano.DocumentGetResponse & RedmineTypes.Issue,
  ): RedmineTypes.Journal[] {
    if (
      (!prev || !prev.journals || prev.journals.length === 0) &&
      current?.journals
    ) {
      return current.journals;
    } else if (prev?.journals && current?.journals) {
      return this.calcJournalsDiff(prev?.journals, current?.journals);
    }
    return [];
  }

  private calcJournalsDiff(
    prev: RedmineTypes.Journal[],
    current: RedmineTypes.Journal[],
  ): RedmineTypes.Journal[] {
    const res: RedmineTypes.Journal[] = [];

    const prevIds = prev.map((item) => item.id);

    for (let i = 0; i < current.length; i++) {
      const currentItem = current[i];
      if (!prevIds.includes(currentItem.id)) {
        res.push(currentItem);
      }
    }
    return res;
  }
}
