import React from 'react';
import * as DashboardStoreNs from '../dashboard-store';
import { observer } from 'mobx-react-lite';
import { DebugInfo } from '../../misc-components/debug-info';
import { Instance, onSnapshot, types } from 'mobx-state-tree';
import { v4 as uuidv4 } from 'uuid';
import { text2id } from '../../utils/text-to-id';

export const DailyEccmV2Data = types.model({
  id: types.string,
  dashboardId: types.string,
  widgetId: types.string,
  datetime: types.number,
  datetimeFormatted: types.string,
  reportIssues: types.array(types.frozen()),
  issuesMetrics: types.frozen(),
  latest: types.boolean,
});

export const DailyEccmV2Store = types
  .model({
    data: DailyEccmV2Data,
  })
  .actions((self) => ({
    setData(data: any) {
      self.data = data;
    },
  }));

export type IDailyEccmV2Store = Instance<typeof DailyEccmV2Store>;

const SimpleCounterViewComponent = (props: {
  id: string;
  label: string;
  count: number;
  issueIds?: number[];
  detailsLabel?: string;
  details?: Record<string, number>;
}): JSX.Element => {
  let detailsHintComponent = <></>;
  if (props.details) {
    const parentKey = props.id
      ? props.id
      : `simple-counter-component-${uuidv4()}`;
    const detailsKey = `${parentKey}-details`;
    detailsHintComponent = (
      <DetailsHintViewComponent
        key={detailsKey}
        id={detailsKey}
        mainLabel={props.detailsLabel ?? 'Details'}
        details={props.details}
      />
    );
  }
  return (
    <span key={props.id}>
      {props.label}: {props.count} {detailsHintComponent}
    </span>
  );
};

const DetailsHintViewComponent = (props: {
  id: string;
  mainLabel: string;
  details: Record<string, number>;
}): JSX.Element => {
  return (
    <span key={props.id} style={{ marginLeft: '10px', color: 'lightgray' }}>
      ({props.mainLabel}: {JSON.stringify(props.details)})
    </span>
  );
};

const ChangesCounterTotalViewComponent = (props: {
  id: string;
  data: Record<string, any>;
}): JSX.Element => {
  if (!props.id) return <></>;
  const titles: Record<string, string> = {
    byIssue: 'По задачам',
    byStatus: 'По статусам',
    byVersion: 'По версиям',
    byUserName: 'По работникам',
  };
  const groups = Object.keys(titles);
  const details: JSX.Element[] = [];
  groups.forEach((groupName) => {
    const groupKey = `${props.id}-details-${groupName}`;
    const groupTitle = titles[groupName];
    const groupData = props.data[groupName];
    const cmp = (
      <ChangesCounterListViewComponent
        key={groupKey}
        id={groupKey}
        title={groupTitle}
        data={groupData}
      />
    );
    details.push(cmp);
  });
  return (
    <ul>
      <li>Итого изменений: {props.data?.totalChanges ?? 0}</li>
      <li>Итого комментариев: {props.data?.totalComments ?? 0}</li>
      {details}
    </ul>
  );
};

const ChangesCounterListViewComponent = (props: {
  id: string;
  title: string;
  data?: Record<string, { changes: number; comments: number }>;
}): JSX.Element => {
  if (!props.data || !props.id) return <></>;
  const dataKeys = Object.keys(props.data ?? {});
  if (!dataKeys || dataKeys.length <= 0) return <></>;

  const res: JSX.Element[] = [];

  dataKeys.forEach((itemKey) => {
    const itemData = props.data && props.data[itemKey];
    if (!itemData) return;
    const key = `${props.id}-${text2id(props.title)}-${text2id(itemKey)}`;
    res.push(
      <li key={`${key}-li`}>
        <ChangesCounterItemViewComponent
          key={key}
          id={key}
          label={itemKey}
          type={itemKey === 'byIssue' ? 'issue' : 'other'}
          changes={itemData.changes}
          comments={itemData.comments}
        />
      </li>,
    );
  });

  return (
    <>
      {props.title}:<ul>{res}</ul>
    </>
  );
};

const ChangesCounterItemViewComponent = (props: {
  id: string;
  type: 'issue' | 'other';
  label: string;
  changes: number;
  comments: number;
}): JSX.Element => {
  return (
    <span key={props.id}>
      <span>
        {props.type == 'issue' ? '#' : ''}
        {props.label}:&nbsp;
      </span>
      <span>все изменения - {props.changes}</span>,&nbsp;
      <span>комментарии - {props.comments}</span>
    </span>
  );
};

const VerySimpleCounterViewComponent = (props: {
  id: string;
  title: string;
  value: number | string;
  details?: any;
}): JSX.Element => {
  return (
    <span>
      {props.title}:
      <span style={{ marginLeft: '10px' }}>&nbsp;{props.value}</span>
      <span style={{ marginLeft: '20px', color: 'lightgray' }}>
        &nbsp;{props.details ? JSON.stringify(props.details) : ''}
      </span>
    </span>
  );
};

const VerySimpleCounterListViewComponent = (props: {
  id: string;
  data: { title: string; value: number | string; details?: any }[];
}): JSX.Element => {
  const items: JSX.Element[] = [];
  props.data.forEach((item) => {
    const itemId = `${props.id}-${text2id(item.title)}`;
    items.push(
      <VerySimpleCounterViewComponent
        key={itemId}
        id={itemId}
        title={item.title}
        value={item.value}
        details={item.details}
      />,
    );
  });
  return (
    <ul key={props.id}>
      {items.map((item) => (
        <li key={item.props.id + '-li'}>{item}</li>
      ))}
    </ul>
  );
};

export const DailyEccmV2 = observer(
  (props: { store: IDailyEccmV2Store }): JSX.Element => {
    const dashboardId = props.store?.data?.dashboardId;
    const widgetId = props.store?.data?.widgetId;
    if (!dashboardId || !widgetId) return <></>;

    const keyPrefix = `dashboard-${dashboardId}-widget-${widgetId}`;

    const issuesByStatusCount: Record<string, any> =
      props.store?.data?.issuesMetrics?.issuesByStatusCount ?? {};
    const issuesByVersionsCount: Record<string, any> =
      props.store?.data?.issuesMetrics?.issuesByVersionsCount ?? {};
    const issuesByUsername: Record<string, any> =
      props.store?.data?.issuesMetrics?.issuesByUsername ?? {};
    const changesCount: Record<string, any> =
      props.store?.data?.issuesMetrics?.changesCount ?? {};

    const otherData: {
      title: string;
      value: number | string;
      details?: any;
    }[] = [];

    // ШАГ 1. Количество задач по статусам
    const issuesByStatusCount2 =
      props.store?.data?.issuesMetrics?.issuesByStatusCount ?? {};
    const issuesByStatusCount2Prefix = `Счётчики с количеством задач по статусам`;
    Object.keys(issuesByStatusCount2).forEach((statusName) => {
      const statusData = issuesByStatusCount2[statusName];
      if (statusData) {
        otherData.push({
          title: `${issuesByStatusCount2Prefix} / ${statusName} / Количество задач`,
          value: statusData.count,
          details: {
            issueIds: statusData.issueIds,
          },
        });
        const byVersions = statusData.byVersion;
        const byVersionsPrefix = `${issuesByStatusCount2Prefix} / ${statusName} / По версиям`;
        if (byVersions) {
          Object.keys(byVersions).forEach((versionName) => {
            otherData.push({
              title: `${byVersionsPrefix} / ${versionName} / Количество задач`,
              value: byVersions[versionName].count,
              details: {
                issueIds: byVersions[versionName].issueIds,
              },
            });
          });
        }
      }
    });

    // ШАГ 2. Количество  задач по версиям
    const issuesByVersionCount2 =
      props.store?.data?.issuesMetrics?.issuesByVersionsCount ?? {};
    const issuesByVersionCount2Prefix = 'Счётчики по версиям';
    Object.keys(issuesByVersionCount2).forEach((versionName) => {
      const versionData = issuesByVersionCount2[versionName];
      if (versionData) {
        otherData.push({
          title: `${issuesByVersionCount2Prefix} / ${versionName} / Количество задач`,
          value: versionData.count,
          details: {
            issueIds: versionData.issueIds,
          },
        });
        const byStatuses = versionData.byStatus;
        const byStatusesPrefix = `${issuesByVersionCount2Prefix} / ${versionName} / По статусам`;
        if (byStatuses) {
          Object.keys(byStatuses).forEach((statusName) => {
            otherData.push({
              title: `${byStatusesPrefix} / ${statusName} / Количество задач`,
              value: byStatuses[statusName].count,
              details: {
                issueIds: byStatuses[statusName].issueIds,
              },
            });
          });
        }
      }
    });

    // ШАГ 3. Количество задач по работникам
    const issuesByUsername2 =
      props.store?.data?.issuesMetrics?.issuesByUsername ?? {};
    const issuesByUsername2Prefix = 'Счётчики по работникам';
    Object.keys(issuesByUsername2).forEach((username) => {
      const userData = issuesByUsername2[username];
      if (userData) {
        otherData.push({
          title: `${issuesByUsername2Prefix} / ${username} / Количество задач`,
          value: userData.count,
          details: {
            issueIds: userData.issueIds,
          },
        });
      }
    });

    // ШАГ 4. Количество внутренних изменений
    const changesCount2 = props.store?.data?.issuesMetrics?.changesCount ?? {};
    const changesCount2Prefix = 'Счётчики изменений';
    otherData.push({
      title: `${changesCount2Prefix} / Всего изменений`,
      value: changesCount2.totalChanges || 0,
    });
    otherData.push({
      title: `${changesCount2Prefix} / Всего комментариев`,
      value: changesCount2.totalComments || 0,
    });
    const sections: Record<string, string> = {
      byIssue: 'По задачам',
      byStatus: 'По статусам',
      byVersion: 'По версиям',
      byUserName: 'По работникам',
    };
    Object.keys(sections).forEach((sectionName) => {
      const sectionData = changesCount2[sectionName];
      if (!sectionData) return;
      const sectionPrefix = `${changesCount2Prefix} / ${sections[sectionName]}`;
      Object.keys(sectionData).forEach((itemKey) => {
        const itemData = sectionData[itemKey];
        otherData.push({
          title: `${sectionPrefix} / ${itemKey} / Изменения`,
          value: itemData.changes || 0,
        });
        otherData.push({
          title: `${sectionPrefix} / ${itemKey} / Комментарии`,
          value: itemData.comments || 0,
        });
      });
    });

    // ШАГ 5. Количество задач с оценками трудозатрат
    const issuesWithEstimatesAndSpenthoursCount =
      props.store?.data?.issuesMetrics?.issuesWithEstimatesAndSpenthoursCount ??
      {};

    const estimatesPrefix =
      'Счётчики с оценкой трудозатрат и потраченных часов';

    if (issuesWithEstimatesAndSpenthoursCount.withEstimates) {
      otherData.push({
        title: `${estimatesPrefix} / С оценкой трудозатрат`,
        value: issuesWithEstimatesAndSpenthoursCount.withEstimates.count,
        details: {
          issueIds:
            issuesWithEstimatesAndSpenthoursCount.withEstimates.issueIds,
        },
      });
    }
    if (issuesWithEstimatesAndSpenthoursCount.withoutEstimates) {
      otherData.push({
        title: `${estimatesPrefix} / Без оценки трудозатрат`,
        value: issuesWithEstimatesAndSpenthoursCount.withoutEstimates.count,
        details: {
          issueIds:
            issuesWithEstimatesAndSpenthoursCount.withoutEstimates.issueIds,
        },
      });
    }
    if (issuesWithEstimatesAndSpenthoursCount.withSpentHoursOverEstimates) {
      otherData.push({
        title: `${estimatesPrefix} / С потраченными часами больше, чем оценка трудозатрат`,
        value:
          issuesWithEstimatesAndSpenthoursCount.withSpentHoursOverEstimates
            .count,
        details: {
          issueIds:
            issuesWithEstimatesAndSpenthoursCount.withSpentHoursOverEstimates
              .issueIds,
        },
      });
    }
    if (issuesWithEstimatesAndSpenthoursCount.byVersion) {
      const estimatesPrefixVersions = `${estimatesPrefix} / По версиям`;
      Object.keys(issuesWithEstimatesAndSpenthoursCount.byVersion).forEach(
        (versionName) => {
          const estimatesPrefixVersion = `${estimatesPrefixVersions} / ${versionName}`;
          const versionData =
            issuesWithEstimatesAndSpenthoursCount.byVersion[versionName];
          if (versionData.withEstimates) {
            otherData.push({
              title: `${estimatesPrefixVersion} / С оценкой трудозатрат`,
              value: versionData.withEstimates.count,
              details: { issueIds: versionData.withEstimates.issueIds },
            });
          }
          if (versionData.withoutEstimates) {
            otherData.push({
              title: `${estimatesPrefixVersion} / Без оценки трудозатрат`,
              value: versionData.withoutEstimates.count,
              details: { issueIds: versionData.withoutEstimates.issueIds },
            });
          }
          if (versionData.withSpentHoursOverEstimates) {
            otherData.push({
              title: `${estimatesPrefixVersion} / С потраченными часами больше, чем оценка трудозатрат`,
              value: versionData.withSpentHoursOverEstimates.count,
              details: {
                issueIds: versionData.withSpentHoursOverEstimates.issueIds,
              },
            });
          }
        },
      );
    }
    if (issuesWithEstimatesAndSpenthoursCount.byStatus) {
      const estimatesPrefixStatuses = `${estimatesPrefix} / По статусам`;
      Object.keys(issuesWithEstimatesAndSpenthoursCount.byStatus).forEach(
        (statusName) => {
          const estimatesPrefixStatus = `${estimatesPrefixStatuses} / ${statusName}`;
          const statusData =
            issuesWithEstimatesAndSpenthoursCount.byStatus[statusName];
          if (statusData.withEstimates) {
            otherData.push({
              title: `${estimatesPrefixStatus} / С оценкой трудозатрат`,
              value: statusData.withEstimates.count,
              details: { issueIds: statusData.withEstimates.issueIds },
            });
          }
          if (statusData.withoutEstimates) {
            otherData.push({
              title: `${estimatesPrefixStatus} / Без оценки трудозатрат`,
              value: statusData.withoutEstimates.count,
              details: { issueIds: statusData.withoutEstimates.issueIds },
            });
          }
          if (statusData.withSpentHoursOverEstimates) {
            otherData.push({
              title: `${estimatesPrefixStatus} / С потраченными часами больше, чем оценка трудозатрат`,
              value: statusData.withSpentHoursOverEstimates.count,
              details: {
                issueIds: statusData.withSpentHoursOverEstimates.issueIds,
              },
            });
          }
        },
      );
    }

    const byStatusLi: JSX.Element[] = [];

    Object.keys(issuesByStatusCount).forEach((statusName) => {
      const byStatusData = issuesByStatusCount[statusName];
      const keyPrefixForCurrentStatusBlock = `${keyPrefix}-issuesByStatusCount-${statusName}`;
      byStatusLi.push(
        <li key={`${keyPrefixForCurrentStatusBlock}-li`}>
          <SimpleCounterViewComponent
            key={keyPrefixForCurrentStatusBlock}
            id={keyPrefixForCurrentStatusBlock}
            label={statusName}
            count={byStatusData.count}
            issueIds={byStatusData.issueIds}
            details={byStatusData.byVersion}
            detailsLabel="Версии"
          />
        </li>,
      );
    });

    const byVersionsLi: JSX.Element[] = [];

    Object.keys(issuesByVersionsCount).forEach((versionName) => {
      const byVersionData = issuesByVersionsCount[versionName];
      const keyPrefixForCurrentVersionBlock = `${keyPrefix}-issuesByVersionCount-${versionName}`;
      byVersionsLi.push(
        <li key={`${keyPrefixForCurrentVersionBlock}-li`}>
          <SimpleCounterViewComponent
            key={keyPrefixForCurrentVersionBlock}
            id={keyPrefixForCurrentVersionBlock}
            label={versionName}
            count={byVersionData.count}
            issueIds={byVersionData.issueIds}
            details={byVersionData.byStatus}
            detailsLabel="Статусы"
          />
        </li>,
      );
    });

    const byUsersLi: JSX.Element[] = [];

    Object.keys(issuesByUsername).forEach((username) => {
      const byUserNameData = issuesByUsername[username];
      const keyPrefixForCurrentUserBlock = `${keyPrefix}-issuesByUsername-${username}`;
      byUsersLi.push(
        <li key={`${keyPrefixForCurrentUserBlock}-li`}>
          <SimpleCounterViewComponent
            key={keyPrefixForCurrentUserBlock}
            id={keyPrefixForCurrentUserBlock}
            label={username}
            count={byUserNameData.count}
            issueIds={byUserNameData.issueIds}
          />
        </li>,
      );
    });

    return (
      <div>
        <h1>Daily ECCM V2</h1>
        <p>Дата выгрузки: {props.store?.data?.datetimeFormatted}</p>
        <p>Метрики:</p>
        <ul>
          <li>
            Простые счётчики:
            <ul>
              <li>
                По статусам:
                <ul>{byStatusLi}</ul>
              </li>
              <li>
                По версиям:
                <ul>{byVersionsLi}</ul>
              </li>
              <li>
                По работникам:
                <ul>{byUsersLi}</ul>
              </li>
            </ul>
          </li>
          <li>
            По изменениям в задачах за период:
            <ChangesCounterTotalViewComponent
              key={`${keyPrefix}-changesCounterTotal`}
              id={`${keyPrefix}-changesCounterTotal`}
              data={changesCount}
            />
          </li>
          <li>
            Другие счётчики:
            <VerySimpleCounterListViewComponent
              key={`${keyPrefix}-verySimpleCounterListViewComponent`}
              id={`${keyPrefix}-verySimpleCounterListViewComponent`}
              data={otherData || []}
            />
          </li>
        </ul>
        <DebugInfo value={JSON.stringify(props.store?.data, null, 2)} />
      </div>
    );
  },
);

export type Props = {
  store: DashboardStoreNs.IWidget;
};

export const DailyEccmV2Widget = observer((props: Props): JSX.Element => {
  const dailyEccmV2Store = DailyEccmV2Store.create();
  onSnapshot(props.store, (storeState) => {
    if (storeState.data) {
      dailyEccmV2Store.setData(storeState.data);
    }
  });
  return (
    <>
      <DailyEccmV2 store={dailyEccmV2Store} />
    </>
  );
});
