import {
  createEffect,
  createMemo,
  createSignal,
  on,
  onCleanup,
  onMount,
} from "solid-js";
import AccountSidebar from "~/components/account/AccountSidebar";
import AddAccountDialog, {
  type LoginForm,
} from "~/components/account/AddAccountDialog";
import CourseWorkspace from "~/components/account/CourseWorkspace";
import {
  createWkClient,
  loginApi,
  runStudyQueue,
  type CourseKind,
  type RecordType,
} from "~/service/wk";
import { setUnauthorizedHandler } from "~/service/http";
import { accountStore, type AccountItem } from "~/store/account";
import { getMergedHosts, settingsStore } from "~/store/settings";
import type { CourseType } from "~/types/Course";

const statusOptions: { label: string; value: CourseKind }[] = [
  { label: "我的课程", value: "run" },
  { label: "已结束", value: "finish" },
  { label: "报名中", value: "sign" },
];

const recordTypeOptions: { label: string; value: RecordType }[] = [
  { label: "课程", value: "" },
  { label: "作业", value: "/work" },
  { label: "考试", value: "/exam" },
  { label: "讨论", value: "/discuss" },
];

const createDefaultForm = (host: string): LoginForm => ({
  username: "",
  password: "",
  token: "",
  status: "run",
  host,
});

const stripHtml = (value: string) => value.replace(/<[^>]+>/g, "").trim();

const parseDurationToSeconds = (value: string) => {
  const parts = value.split(":").map(Number);
  if (parts.length !== 3 || parts.some((part) => Number.isNaN(part))) {
    return 0;
  }

  const [hours, minutes, seconds] = parts;
  return hours * 3600 + minutes * 60 + seconds;
};

const createRecordCacheKey = (
  accountId: string,
  courseId: number,
  recordType: RecordType,
) => `${accountId}::${courseId}::${recordType || "course"}`;

const Account = () => {
  const [storeState, setStoreState] = createSignal(accountStore.getState());
  const [settingsState, setSettingsState] = createSignal(
    settingsStore.getState(),
  );
  const [showDialog, setShowDialog] = createSignal(false);
  const [isSubmitting, setIsSubmitting] = createSignal(false);
  const [loggingOutId, setLoggingOutId] = createSignal("");
  const [isRefreshingAccount, setIsRefreshingAccount] = createSignal(false);
  const [errorMessage, setErrorMessage] = createSignal("");
  const [form, setForm] = createSignal<LoginForm>(
    createDefaultForm("cqcst.leykeji.com"),
  );
  const [recordsLoading, setRecordsLoading] = createSignal(false);
  const [recordError, setRecordError] = createSignal("");
  const [isRefreshingRecords, setIsRefreshingRecords] = createSignal(false);
  const [isRefreshingCourses, setIsRefreshingCourses] = createSignal(false);
  const [isRefreshingLogs, setIsRefreshingLogs] = createSignal(false);
  const [hasRestoredRecords, setHasRestoredRecords] = createSignal(false);
  const accountClients = new Map<string, ReturnType<typeof createWkClient>>();

  onMount(() => {
    const unsubscribeAccount = accountStore.subscribe((state) => {
      setStoreState(state);
    });
    const unsubscribeSettings = settingsStore.subscribe((state) => {
      setSettingsState(state);
    });
    setUnauthorizedHandler(reloginBySession);

    onCleanup(() => {
      unsubscribeAccount();
      unsubscribeSettings();
      setUnauthorizedHandler(null);
    });
  });

  const accounts = createMemo(() => storeState().accounts);
  const selectedAccountId = createMemo(() => storeState().selectedAccountId);
  const expandedAccountId = createMemo(() => storeState().expandedAccountId);
  const selectedCourseId = createMemo(() => storeState().selectedCourseId);
  const courseKind = createMemo(() => storeState().courseKind);
  const recordType = createMemo(() => storeState().recordType);
  const records = createMemo(() => storeState().records);
  const recordCacheMap = createMemo(() => storeState().recordCacheMap);
  const studyLogsMap = createMemo(() => storeState().studyLogsMap);
  const runningStudyMap = createMemo(() => storeState().runningStudyMap);
  const mergedHostOptions = createMemo(() =>
    getMergedHosts(settingsState().localHosts, settingsState().remoteHosts),
  );
  const hostLabels = createMemo(
    () =>
      Object.fromEntries(
        mergedHostOptions().map((item) => [item.host, item.label]),
      ) as Record<string, string>,
  );
  const defaultHost = createMemo(
    () => mergedHostOptions()[0]?.host ?? "cqcst.leykeji.com",
  );
  const currentCourseKindLabel = createMemo(
    () =>
      statusOptions.find((item) => item.value === courseKind())?.label ??
      courseKind(),
  );
  const showingCachedRecords = createMemo(() => {
    const accountId = selectedAccountId();
    const courseId = selectedCourseId();

    if (!accountId || !courseId || recordsLoading() || isRefreshingRecords()) {
      return false;
    }

    return (
      createRecordCacheKey(accountId, courseId, recordType()) in
      recordCacheMap()
    );
  });

  const selectedAccount = createMemo(() => {
    return accounts().find((item) => item.id === selectedAccountId()) ?? null;
  });

  const selectedCourseList = createMemo<CourseType[]>(() => {
    return selectedAccount()?.courses ?? [];
  });

  const selectedCourse = createMemo(() => {
    return (
      selectedCourseList().find((item) => item.id === selectedCourseId()) ??
      null
    );
  });

  const isRunningStudy = createMemo(() => {
    const account = selectedAccount();
    if (!account) {
      return false;
    }

    return !!runningStudyMap()[account.id];
  });

  const studyLogs = createMemo(() => {
    const account = selectedAccount();
    if (!account) {
      return [];
    }

    return studyLogsMap()[account.id] ?? [];
  });

  const updateForm = <K extends keyof LoginForm>(
    key: K,
    value: LoginForm[K],
  ) => {
    setForm((prev) => ({ ...prev, [key]: value }));
  };

  const appendStudyLog = (message: string, accountId?: string) => {
    const targetAccountId = accountId ?? selectedAccount()?.id;
    if (!targetAccountId) {
      return;
    }

    accountStore.getState().appendStudyLog(targetAccountId, message);
  };

  const getAccountClient = (accountId: string) => {
    const existingClient = accountClients.get(accountId);
    if (existingClient) {
      return existingClient;
    }

    const client = createWkClient(() => {
      return accountStore
        .getState()
        .accounts.find((item) => item.id === accountId)?.sessionId;
    });

    accountClients.set(accountId, client);
    return client;
  };

  const reloginBySession = async (sessionId: string) => {
    if (!sessionId) {
      return false;
    }

    const target = accountStore
      .getState()
      .accounts.find((item) => item.sessionId === sessionId);

    if (!target) {
      return false;
    }

    try {
      const res = await loginApi({
        username: target.username,
        password: target.auth.password,
        token: target.auth.token,
        status: target.status,
        host: target.host,
      });

      accountStore.getState().upsertAccount({
        ...target,
        sessionId: res.data.session_id,
        user: res.data.user,
        courses: res.data.courses ?? target.courses,
      });
      await loadCourses(target.id, target.status);
      appendStudyLog(`会话失效，已重新登录：${target.user.name}`, target.id);
      return true;
    } catch (error) {
      const message = error instanceof Error ? error.message : "重新登录失败";
      setErrorMessage(message);
      appendStudyLog(`重新登录失败：${message}`, target.id);
      return false;
    }
  };

  const openDialog = () => {
    setErrorMessage("");
    setForm(createDefaultForm(defaultHost()));
    setShowDialog(true);
  };

  const closeDialog = () => {
    if (isSubmitting()) {
      return;
    }

    setShowDialog(false);
    setErrorMessage("");
  };

  const handleAddAccount = async () => {
    const payload = form();
    const hasAccount =
      payload.username.trim() !== "" && payload.password.trim() !== "";
    const hasCookie = payload.token.trim() !== "";

    if (!hasAccount && !hasCookie) {
      setErrorMessage("请填写账号和密码，或者填写 Cookie。");
      return;
    }

    setIsSubmitting(true);
    setErrorMessage("");

    try {
      const res = await loginApi({
        username: payload.username.trim(),
        password: payload.password.trim(),
        token: payload.token.trim(),
        status: payload.status,
        host: payload.host,
      });

      const accountId = `${res.data.user.id}-${payload.host}-${payload.status}`;
      const nextAccount: AccountItem = {
        id: accountId,
        username: payload.username.trim() || res.data.user.id,
        host: payload.host,
        status: payload.status,
        sessionId: res.data.session_id,
        auth: {
          password: payload.password.trim(),
          token: payload.token.trim(),
        },
        user: res.data.user,
        courses: res.data.courses ?? [],
      };

      accountStore.getState().upsertAccount(nextAccount);
      await loadCourses(nextAccount.id, nextAccount.status);
      accountStore.getState().setSelectedCourseId(null);
      accountStore.getState().setRecords([]);
      setShowDialog(false);
      setForm(createDefaultForm(defaultHost()));
    } catch (error) {
      const message =
        error instanceof Error ? error.message : "登录失败，请检查输入信息。";
      setErrorMessage(message);
    } finally {
      setIsSubmitting(false);
    }
  };

  const handleSelectAccount = (accountId: string) => {
    accountStore.getState().setSelectedAccountId(accountId);
    accountStore.getState().setSelectedCourseId(null);
    accountStore.getState().setRecords([]);
    setRecordError("");
  };

  const handleToggleExpand = (accountId: string) => {
    const nextId = expandedAccountId() === accountId ? "" : accountId;
    accountStore.getState().setExpandedAccountId(nextId);
  };

  const loadCourses = async (
    accountId = selectedAccount()?.id,
    status = courseKind(),
  ) => {
    if (!accountId) {
      return;
    }

    setIsRefreshingCourses(true);
    setErrorMessage("");

    try {
      const res = await getAccountClient(accountId).courseApi({ status });
      const courses = res.data.courses ?? [];
      const account = accountStore
        .getState()
        .accounts.find((item) => item.id === accountId);

      accountStore.getState().setAccountCourses(accountId, courses);

      const currentCourseId = accountStore.getState().selectedCourseId;
      if (account?.id === accountStore.getState().selectedAccountId) {
        const hasSelectedCourse = courses.some(
          (item) => item.id === currentCourseId,
        );
        if (!hasSelectedCourse) {
          accountStore.getState().setSelectedCourseId(courses[0]?.id ?? null);
          accountStore.getState().setRecords([]);
        }
      }
    } catch (error) {
      const message =
        error instanceof Error ? error.message : "获取课程失败，请稍后重试。";
      setErrorMessage(message);
      accountStore.getState().setAccountCourses(accountId, []);
      if (accountStore.getState().selectedAccountId === accountId) {
        accountStore.getState().setSelectedCourseId(null);
        accountStore.getState().setRecords([]);
      }
    } finally {
      setIsRefreshingCourses(false);
    }
  };

  const handleRefreshAccount = async () => {
    const account = selectedAccount();
    if (!account) {
      setErrorMessage("请先选择账号。");
      return;
    }

    setIsRefreshingAccount(true);
    setErrorMessage("");

    try {
      const res = await loginApi({
        username: account.username,
        password: account.auth.password,
        token: account.auth.token,
        status: account.status,
        host: account.host,
      });

      accountStore.getState().upsertAccount({
        ...account,
        sessionId: res.data.session_id,
        user: res.data.user,
        courses: res.data.courses ?? account.courses,
      });
      await loadCourses(account.id, account.status);
    } catch (error) {
      const message =
        error instanceof Error ? error.message : "刷新账号失败，请稍后重试。";
      setErrorMessage(message);
    } finally {
      setIsRefreshingAccount(false);
    }
  };

  const handleLogout = async (accountId: string) => {
    setLoggingOutId(accountId);

    try {
      const target = accounts().find((item) => item.id === accountId);
      if (!target) {
        return;
      }

      await getAccountClient(accountId).logoutApi();
      accountClients.delete(accountId);

      accountStore.getState().removeAccount(accountId);
      if (selectedAccountId() === accountId) {
        accountStore.getState().setSelectedCourseId(null);
        accountStore.getState().setRecords([]);
      }
    } catch (error) {
      const message =
        error instanceof Error ? error.message : "退出登录失败，请稍后重试。";
      setErrorMessage(message);
    } finally {
      setLoggingOutId("");
    }
  };

  const loadCourseRecords = async (
    courseId: number,
    nextRecordType = recordType(),
  ) => {
    const account = selectedAccount();
    if (!account) {
      return;
    }

    setRecordsLoading(true);
    setIsRefreshingRecords(true);
    setRecordError("");

    try {
      const res = await getAccountClient(account.id).recordApi({
        course_id: String(courseId),
        page: 0,
        record_type: nextRecordType,
      });
      accountStore.getState().setRecords(res.data.list);
      accountStore
        .getState()
        .setRecordCache(
          createRecordCacheKey(account.id, courseId, nextRecordType),
          res.data.list,
        );
    } catch (error) {
      const message =
        error instanceof Error ? error.message : "获取记录失败，请稍后重试。";
      setRecordError(message);
      accountStore.getState().setRecords([]);
    } finally {
      setRecordsLoading(false);
      setIsRefreshingRecords(false);
    }
  };

  const handleSelectCourse = (courseId: number) => {
    accountStore.getState().setSelectedCourseId(courseId);
  };

  const handleRefreshRecords = async () => {
    const courseId = selectedCourseId();
    if (!courseId) {
      setRecordError("请先选择课程。");
      return;
    }

    await loadCourseRecords(courseId);
  };

  const handleClearLogs = () => {
    const account = selectedAccount();
    if (!account) {
      return;
    }

    accountStore.getState().clearStudyLogs(account.id);
  };

  const handleRefreshLogs = () => {
    setIsRefreshingLogs(true);
    appendStudyLog("手动刷新日志面板");
    queueMicrotask(() => {
      setIsRefreshingLogs(false);
    });
  };

  const handleStartStudy = async () => {
    const account = selectedAccount();
    const course = selectedCourse();

    if (!account || !course) {
      setRecordError("请先选择账号和课程。");
      return;
    }

    const queueItems = records()
      .filter((item) => item.progress !== "1.00")
      .map((item) => ({
        nodeId: item.id,
        name: item.name,
        currentTime: Number(item.duration || 0),
        totalTime: parseDurationToSeconds(item.videoDuration),
        progress: item.progress,
        completed: stripHtml(item.state) === "已学",
      }));

    try {
      accountStore.getState().setAccountRunningStudy(account.id, true);
      appendStudyLog(`开始刷课：${course.name}`, account.id);
      await runStudyQueue({
        accountId: account.id,
        courseId: course.id,
        intervalSeconds: 5,
        items: queueItems,
        client: getAccountClient(account.id),
        isRunningStudy: () =>
          !!accountStore.getState().runningStudyMap[account.id],
        setIsRunningStudy: () =>
          accountStore.getState().setAccountRunningStudy(account.id, false),
        onLog: (message: string, accoundID: string) =>
          appendStudyLog(message, accoundID),
      });
      if (accountStore.getState().runningStudyMap[account.id]) {
        appendStudyLog(`刷课完成：${course.name}`, account.id);
      }
    } catch (error) {
      const message =
        error instanceof Error ? error.message : "刷课流程执行失败。";
      appendStudyLog(`刷课失败：${message}`, account.id);
      setRecordError(message);
    } finally {
      accountStore.getState().setAccountRunningStudy(account.id, false);
    }
  };

  const handleStopStudy = () => {
    const account = selectedAccount();
    if (!account) {
      return;
    }

    accountStore.getState().setAccountRunningStudy(account.id, false);
    appendStudyLog(`已发送停止刷课指令：${account.user.name}`, account.id);
  };

  createEffect(
    on([selectedAccountId, courseKind], ([accountId, kind]) => {
      if (!accountId) {
        return;
      }

      void loadCourses(accountId, kind);
    }),
  );

  createEffect(
    on(
      [selectedAccountId, selectedCourseId, recordType],
      ([accountId, courseId, type]) => {
        if (!accountId || !courseId) {
          accountStore.getState().setRecords([]);
          return;
        }

        const cachedRecords =
          recordCacheMap()[createRecordCacheKey(accountId, courseId, type)] ??
          [];
        accountStore.getState().setRecords(cachedRecords);
      },
    ),
  );

  createEffect(() => {
    const courseId = selectedCourseId();
    const account = selectedAccount();
    const type = recordType();
    const cacheKey = account
      ? createRecordCacheKey(account.id, courseId ?? 0, type)
      : "";
    const hasCachedRecords = cacheKey ? cacheKey in recordCacheMap() : false;

    if (!hasRestoredRecords()) {
      setHasRestoredRecords(true);

      if (courseId && account && (records().length > 0 || hasCachedRecords)) {
        return;
      }
    }

    if (!courseId || !account) {
      return;
    }

    if (hasCachedRecords) {
      return;
    }

    void loadCourseRecords(courseId, type);
  });

  return (
    <div class="flex h-full min-h-0 flex-col overflow-hidden">
      <div class="flex shrink-0 items-center justify-between gap-3 rounded-[24px] border border-white/80 bg-[linear-gradient(135deg,rgba(236,254,255,0.95),rgba(255,255,255,0.92))] px-4 py-3 shadow-[0_18px_45px_-28px_rgba(8,145,178,0.35)]">
        <div>
          <p class="text-xs font-medium tracking-[0.26em] text-cyan-700/75 uppercase">
            Account Center
          </p>
          <h1 class="mt-1 text-xl font-semibold text-zinc-900 sm:text-2xl">
            账号管理
          </h1>
          <p class="mt-0.5 text-xs text-zinc-500 sm:text-sm">
            管理账号登录、课程记录与运行日志
          </p>
        </div>

        <button
          class="rounded-xl bg-[linear-gradient(135deg,#06b6d4,#14b8a6)] px-3.5 py-2.5 text-sm font-medium text-white shadow-lg shadow-cyan-500/20 transition hover:-translate-y-px hover:shadow-cyan-500/30"
          onClick={openDialog}
        >
          添加账号
        </button>
      </div>

      <div class="mt-4 flex min-h-0 flex-1 flex-col gap-4 xl:flex-row">
        <AccountSidebar
          accounts={accounts()}
          selectedAccountId={selectedAccountId()}
          expandedAccountId={expandedAccountId()}
          statusOptions={statusOptions}
          currentCourseKind={courseKind()}
          hostLabels={hostLabels()}
          isRefreshingAccount={isRefreshingAccount()}
          loggingOutId={loggingOutId()}
          densityMode={settingsState().densityMode}
          sidebarWidth={settingsState().sidebarWidth}
          onRefreshAccount={() => void handleRefreshAccount()}
          onSelectAccount={handleSelectAccount}
          onToggleExpand={handleToggleExpand}
          onLogout={(accountId) => void handleLogout(accountId)}
        />

        <CourseWorkspace
          selectedAccount={selectedAccount()}
          selectedCourseList={selectedCourseList()}
          selectedCourseId={selectedCourseId()}
          selectedCourse={selectedCourse()}
          recordType={recordType()}
          courseKind={courseKind()}
          currentCourseKindLabel={currentCourseKindLabel()}
          showingCachedRecords={showingCachedRecords()}
          recordTypeOptions={recordTypeOptions}
          courseRecordTypeOptions={statusOptions}
          records={records()}
          studyLogs={studyLogs()}
          recordsLoading={recordsLoading()}
          recordError={recordError()}
          isRefreshingRecords={isRefreshingRecords()}
          isRefreshingCourseRecords={isRefreshingCourses()}
          isRunningStudy={isRunningStudy()}
          isRefreshingLogs={isRefreshingLogs()}
          autoScrollLogs={settingsState().autoScrollLogs}
          showLogTimestamps={settingsState().showLogTimestamps}
          densityMode={settingsState().densityMode}
          logFontSize={settingsState().logFontSize}
          onSelectCourse={(courseId) => void handleSelectCourse(courseId)}
          onRefreshRecords={() => void handleRefreshRecords()}
          onRefreshCourseRecords={() => void loadCourses()}
          onChangeRecordType={(value) =>
            accountStore.getState().setRecordType(value)
          }
          onChangeCourseRecordType={(value) => {
            accountStore.getState().setCourseKind(value);
            accountStore.getState().setSelectedCourseId(null);
            accountStore.getState().setRecords([]);
          }}
          onStartStudy={() => void handleStartStudy()}
          onStopStudy={handleStopStudy}
          onRefreshLogs={handleRefreshLogs}
          onClearLogs={handleClearLogs}
          renderRecordState={stripHtml}
        />
      </div>

      <AddAccountDialog
        open={showDialog}
        onClose={closeDialog}
        onSubmit={() => void handleAddAccount()}
        isSubmitting={isSubmitting()}
        errorMessage={errorMessage()}
        form={form()}
        statusOptions={statusOptions}
        hostOptions={mergedHostOptions().map((item) => ({
          label: item.label,
          host: item.host,
        }))}
        updateForm={updateForm}
      />
    </div>
  );
};

export default Account;
