"use client";

import { create } from "zustand";
import { persist } from "zustand/middleware";
import {
  createDefaultScopedData,
  createEmptyProject,
  mergeProjectAccounts,
  type ProjectScopedData,
} from "@/lib/project/defaults";
import { MAX_SEQUENCE_POSTS } from "@/lib/context/sequence-templates";
import { migrateLegacyStores, patchScopedContextPosts } from "@/lib/project/migrate-legacy";
import type {
  BrandProfile,
  ConnectedAccount,
  PostingContextData,
  PostSequenceItem,
  Project,
  ProjectStatus,
} from "@/types/workflow";

interface ProjectsState {
  projects: Project[];
  activeProjectId: string | null;
  dataByProjectId: Record<string, ProjectScopedData>;
  _hasHydrated: boolean;
}

interface ProjectsStore extends ProjectsState {
  getActiveProject: () => Project | null;
  getActiveData: () => ProjectScopedData | null;
  getProjectData: (projectId: string) => ProjectScopedData | null;
  switchProject: (projectId: string) => void;
  createProject: (
    input: Omit<Project, "id" | "createdAt" | "updatedAt">,
  ) => string | null;
  updateProject: (projectId: string, data: Partial<Project>) => void;
  deleteProject: (projectId: string) => boolean;
  setActiveProjectStatus: (status: ProjectStatus) => void;
  updateActiveBrand: (data: Partial<BrandProfile>) => void;
  updateActiveContext: (data: Partial<PostingContextData>) => void;
  setActiveContextName: (name: string) => void;
  setActivePosts: (posts: PostSequenceItem[]) => void;
  addActivePost: () => void;
  updateActivePost: (id: string, data: Partial<PostSequenceItem>) => void;
  removeActivePost: (id: string) => void;
  selectActivePost: (id: string | null) => void;
  saveActiveContext: () => void;
  connectActiveAccount: (
    platform: string,
    profileName: string,
    tokens?: {
      accessToken?: string;
      expiresInDays?: number;
      expiresAt?: string;
      externalId?: string;
    },
  ) => void;
  hydrateActiveAccounts: (accounts: ConnectedAccount[]) => void;
  disconnectActiveAccount: (platform: string) => void;
  markAccountExpired: (platform: string) => void;
  updateActiveSchedule: (data: Partial<ProjectScopedData["schedule"]>) => void;
  saveActiveSchedule: () => void;
  setActiveAutomationRule: (ruleId: string, enabled: boolean) => void;
}

function ensureProjectData(
  dataByProjectId: Record<string, ProjectScopedData>,
  projectId: string,
): ProjectScopedData {
  if (!dataByProjectId[projectId]) {
    dataByProjectId[projectId] = createDefaultScopedData();
  } else if (!Array.isArray(dataByProjectId[projectId].accounts)) {
    dataByProjectId[projectId] = {
      ...dataByProjectId[projectId],
      accounts: mergeProjectAccounts(undefined),
    };
  }
  return dataByProjectId[projectId];
}

export const useProjectsStore = create<ProjectsStore>()(
  persist(
    (set, get) => ({
      projects: [],
      activeProjectId: null,
      dataByProjectId: {},
      _hasHydrated: false,

      getActiveProject: () => {
        const { projects, activeProjectId } = get();
        if (!activeProjectId) return null;
        return projects.find((p) => p.id === activeProjectId) ?? null;
      },

      getActiveData: () => {
        const { activeProjectId, dataByProjectId } = get();
        if (!activeProjectId) return null;
        return dataByProjectId[activeProjectId] ?? null;
      },

      getProjectData: (projectId) => get().dataByProjectId[projectId] ?? null,

      switchProject: (projectId) => {
        const exists = get().projects.some((p) => p.id === projectId);
        if (!exists) return;
        set({ activeProjectId: projectId });
      },

      createProject: (input) => {
        const trimmed = input.name.trim();
        if (!trimmed) return null;

        const project = createEmptyProject({ ...input, name: trimmed });
        const data = createDefaultScopedData();
        data.brand.companyName = trimmed;
        data.brand.industry = input.industry;

        set((state) => ({
          projects: [...state.projects, project],
          activeProjectId: project.id,
          dataByProjectId: { ...state.dataByProjectId, [project.id]: data },
        }));

        return project.id;
      },

      updateProject: (projectId, data) => {
        set((state) => ({
          projects: state.projects.map((p) =>
            p.id === projectId
              ? { ...p, ...data, updatedAt: new Date().toISOString() }
              : p,
          ),
        }));
      },

      deleteProject: (projectId) => {
        const { projects, activeProjectId } = get();
        if (projects.length <= 1) return false;

        const nextProjects = projects.filter((p) => p.id !== projectId);
        const nextData = { ...get().dataByProjectId };
        delete nextData[projectId];

        let nextActive = activeProjectId;
        if (activeProjectId === projectId) {
          nextActive = nextProjects[0]?.id ?? null;
        }

        set({
          projects: nextProjects,
          activeProjectId: nextActive,
          dataByProjectId: nextData,
        });
        return true;
      },

      setActiveProjectStatus: (status) => {
        const id = get().activeProjectId;
        if (!id) return;
        get().updateProject(id, { status });
      },

      updateActiveBrand: (data) => {
        const id = get().activeProjectId;
        if (!id) return;
        set((state) => {
          const current = ensureProjectData({ ...state.dataByProjectId }, id);
          return {
            dataByProjectId: {
              ...state.dataByProjectId,
              [id]: { ...current, brand: { ...current.brand, ...data } },
            },
          };
        });
      },

      updateActiveContext: (data) => {
        const id = get().activeProjectId;
        if (!id) return;
        set((state) => {
          const current = ensureProjectData({ ...state.dataByProjectId }, id);
          return {
            dataByProjectId: {
              ...state.dataByProjectId,
              [id]: {
                ...current,
                context: { ...current.context, ...data, saved: false },
              },
            },
          };
        });
      },

      setActiveContextName: (name) => get().updateActiveContext({ name }),

      setActivePosts: (posts) => get().updateActiveContext({ posts }),

      addActivePost: () => {
        const id = get().activeProjectId;
        if (!id) return;
        set((state) => {
          const current = ensureProjectData({ ...state.dataByProjectId }, id);
          // Keep the Post 1→Post 2→… loop model; active sequence size is capped at 5.
          if (current.context.posts.length >= MAX_SEQUENCE_POSTS) return state;
          const nextIndex = current.context.posts.length + 1;
          const newPost: PostSequenceItem = {
            id: `seq-${Date.now()}`,
            title: `Post ${nextIndex} — Custom`,
            summary: "",
            tag: "General",
            content: "",
          };
          return {
            dataByProjectId: {
              ...state.dataByProjectId,
              [id]: {
                ...current,
                context: {
                  ...current.context,
                  posts: [...current.context.posts, newPost],
                  saved: false,
                },
                selectedPostId: newPost.id,
              },
            },
          };
        });
      },

      updateActivePost: (postId, data) => {
        const id = get().activeProjectId;
        if (!id) return;
        set((state) => {
          const current = ensureProjectData({ ...state.dataByProjectId }, id);
          return {
            dataByProjectId: {
              ...state.dataByProjectId,
              [id]: {
                ...current,
                context: {
                  ...current.context,
                  posts: current.context.posts.map((p) =>
                    p.id === postId ? { ...p, ...data } : p,
                  ),
                  saved: false,
                },
              },
            },
          };
        });
      },

      removeActivePost: (postId) => {
        const id = get().activeProjectId;
        if (!id) return;
        set((state) => {
          const current = ensureProjectData({ ...state.dataByProjectId }, id);
          return {
            dataByProjectId: {
              ...state.dataByProjectId,
              [id]: {
                ...current,
                context: {
                  ...current.context,
                  posts: current.context.posts.filter((p) => p.id !== postId),
                  saved: false,
                },
                selectedPostId: null,
              },
            },
          };
        });
      },

      selectActivePost: (postId) => {
        const id = get().activeProjectId;
        if (!id) return;
        set((state) => {
          const current = ensureProjectData({ ...state.dataByProjectId }, id);
          return {
            dataByProjectId: {
              ...state.dataByProjectId,
              [id]: { ...current, selectedPostId: postId },
            },
          };
        });
      },

      saveActiveContext: () => {
        const id = get().activeProjectId;
        if (!id) return;
        set((state) => {
          const current = ensureProjectData({ ...state.dataByProjectId }, id);
          return {
            dataByProjectId: {
              ...state.dataByProjectId,
              [id]: {
                ...current,
                context: { ...current.context, saved: true },
              },
            },
          };
        });
      },

      connectActiveAccount: (
        platform,
        profileName,
        tokens?: {
          accessToken?: string;
          expiresInDays?: number;
          expiresAt?: string;
          externalId?: string;
        },
      ) => {
        const id = get().activeProjectId;
        if (!id) return;

        const now = new Date();
        const expiresAt =
          tokens?.expiresAt ??
          (tokens?.expiresInDays
            ? new Date(now.getTime() + tokens.expiresInDays * 86400000).toISOString()
            : tokens?.accessToken
              ? new Date(now.getTime() + 60 * 86400000).toISOString()
              : null);

        set((state) => {
          const current = ensureProjectData({ ...state.dataByProjectId }, id);
          return {
            dataByProjectId: {
              ...state.dataByProjectId,
              [id]: {
                ...current,
                accounts: mergeProjectAccounts(
                  current.accounts.map((a) =>
                    a.platform === platform
                      ? {
                          ...a,
                          connected: true,
                          profileName,
                          connectionStatus: "connected" as const,
                          accessToken: tokens?.accessToken ?? null,
                          externalId: tokens?.externalId ?? a.externalId ?? null,
                          expiresAt,
                          lastSyncedAt: now.toISOString(),
                        }
                      : a,
                  ),
                ),
              },
            },
          };
        });
      },

      hydrateActiveAccounts: (serverAccounts) => {
        const id = get().activeProjectId;
        if (!id || !serverAccounts.length) return;

        set((state) => {
          const current = ensureProjectData({ ...state.dataByProjectId }, id);
          const byPlatform = new Map(serverAccounts.map((a) => [a.platform, a]));
          return {
            dataByProjectId: {
              ...state.dataByProjectId,
              [id]: {
                ...current,
                accounts: mergeProjectAccounts(
                  current.accounts.map((a) => {
                    const server = byPlatform.get(a.platform);
                    if (!server) return a;
                    return {
                      ...a,
                      connected: server.connected,
                      profileName: server.profileName,
                      // Prefer server status / expiry so a refreshed token clears the local "expired" banner.
                      connectionStatus: server.connectionStatus,
                      expiresAt: server.expiresAt ?? null,
                      externalId: server.externalId ?? a.externalId,
                      lastSyncedAt: server.lastSyncedAt ?? a.lastSyncedAt,
                      accessToken: null,
                      refreshToken: null,
                    };
                  }),
                ),
              },
            },
          };
        });
      },

      disconnectActiveAccount: (platform) => {
        const id = get().activeProjectId;
        if (!id) return;
        set((state) => {
          const current = ensureProjectData({ ...state.dataByProjectId }, id);
          return {
            dataByProjectId: {
              ...state.dataByProjectId,
              [id]: {
                ...current,
                accounts: mergeProjectAccounts(
                  current.accounts.map((a) =>
                    a.platform === platform
                      ? {
                          ...a,
                          connected: false,
                          profileName: "Not connected",
                          connectionStatus: "disconnected" as const,
                          accessToken: null,
                          refreshToken: null,
                          expiresAt: null,
                        }
                      : a,
                  ),
                ),
              },
            },
          };
        });
      },

      markAccountExpired: (platform) => {
        const id = get().activeProjectId;
        if (!id) return;
        set((state) => {
          const current = ensureProjectData({ ...state.dataByProjectId }, id);
          const accounts = Array.isArray(current.accounts) ? current.accounts : [];
          return {
            dataByProjectId: {
              ...state.dataByProjectId,
              [id]: {
                ...current,
                accounts: mergeProjectAccounts(
                  accounts.map((a) =>
                    a.platform === platform
                      ? {
                          ...a,
                          connectionStatus: "expired" as const,
                          expiresAt: new Date(0).toISOString(),
                        }
                      : a,
                  ),
                ),
              },
            },
          };
        });
      },

      updateActiveSchedule: (data) => {
        const id = get().activeProjectId;
        if (!id) return;
        set((state) => {
          const current = ensureProjectData({ ...state.dataByProjectId }, id);
          return {
            dataByProjectId: {
              ...state.dataByProjectId,
              [id]: {
                ...current,
                schedule: { ...current.schedule, ...data, saved: false },
              },
            },
          };
        });
      },

      saveActiveSchedule: () => {
        const id = get().activeProjectId;
        if (!id) return;
        set((state) => {
          const current = ensureProjectData({ ...state.dataByProjectId }, id);
          return {
            dataByProjectId: {
              ...state.dataByProjectId,
              [id]: {
                ...current,
                schedule: {
                  ...current.schedule,
                  saved: true,
                  scheduleSeed: Date.now() % 997,
                },
              },
            },
          };
        });
      },

      setActiveAutomationRule: (ruleId, enabled) => {
        const id = get().activeProjectId;
        if (!id) return;
        set((state) => {
          const current = ensureProjectData({ ...state.dataByProjectId }, id);
          return {
            dataByProjectId: {
              ...state.dataByProjectId,
              [id]: {
                ...current,
                automation: { ...current.automation, [ruleId]: enabled },
              },
            },
          };
        });
      },
    }),
    {
      name: "postsync-projects",
      version: 1,
      partialize: (state) => ({
        projects: state.projects,
        activeProjectId: state.activeProjectId,
        dataByProjectId: state.dataByProjectId,
      }),
      merge: (persisted, current) => {
        const p = persisted as Partial<ProjectsState> | undefined;
        if (!p || !Array.isArray(p.projects) || !p.projects.length) return current as ProjectsStore;

        const dataByProjectId = { ...(p.dataByProjectId ?? {}) };
        for (const project of p.projects) {
          if (!dataByProjectId[project.id]) {
            dataByProjectId[project.id] = createDefaultScopedData();
          } else {
            dataByProjectId[project.id] = {
              ...dataByProjectId[project.id],
              accounts: mergeProjectAccounts(dataByProjectId[project.id].accounts),
              context: dataByProjectId[project.id].context?.posts
                ? {
                    ...dataByProjectId[project.id].context,
                    posts: patchScopedContextPosts(
                      dataByProjectId[project.id].context.posts as Parameters<
                        typeof patchScopedContextPosts
                      >[0],
                    ),
                  }
                : dataByProjectId[project.id].context,
            };
          }
        }

        return {
          ...current,
          ...p,
          dataByProjectId,
          _hasHydrated: false,
        } as ProjectsStore;
      },
      onRehydrateStorage: () => (state) => {
        if (!state) return;

        if (!Array.isArray(state.projects)) {
          state.projects = [];
        }

        if (state.projects.length === 0) {
          try {
            const legacyProject = JSON.parse(
              localStorage.getItem("postsync-project") ?? "null",
            ) as { state?: { project?: unknown } } | null;
            const legacyBrand = JSON.parse(
              localStorage.getItem("postsync-brand") ?? "null",
            ) as { state?: { brand?: unknown } } | null;
            const legacyContext = JSON.parse(
              localStorage.getItem("postsync-context") ?? "null",
            ) as {
              state?: { context?: PostingContextData; selectedPostId?: string | null };
            } | null;
            const legacyAccounts = JSON.parse(
              localStorage.getItem("postsync-accounts") ?? "null",
            ) as { state?: { accounts?: ConnectedAccount[] } } | null;

            const migrated = migrateLegacyStores({
              legacyProject: legacyProject?.state?.project as Parameters<
                typeof migrateLegacyStores
              >[0]["legacyProject"],
              legacyBrand: legacyBrand?.state?.brand as BrandProfile | undefined,
              legacyContext: legacyContext?.state ?? null,
              legacyAccounts: legacyAccounts?.state ?? null,
            });

            if (migrated.projects.length) {
              state.projects = migrated.projects;
              state.activeProjectId = migrated.activeProjectId;
              state.dataByProjectId = migrated.dataByProjectId;
            }
          } catch {
            // ignore corrupt legacy storage
          }
        }

        state._hasHydrated = true;
      },
    },
  ),
);

export function projectToLegacyContext(project: Project): {
  id: string;
  name: string;
  website: string;
  industry: string;
  timezone: string;
  countries: string[];
  status: ProjectStatus;
  created: boolean;
} {
  return { ...project, created: true };
}

export const emptyLegacyProject = {
  id: "",
  name: "",
  website: "",
  industry: "Technology / Software",
  timezone: "America/New_York (EST)",
  countries: ["US", "GB", "IN", "CA"],
  status: "active" as ProjectStatus,
  created: false,
};
