import type {
  CreatePersonalAccessTokenResponse,
  PersonalAccessToken,
  User,
  UserNotification,
  UserSetting,
  UserStats,
  UserWebhook,
  UserSetting_GeneralSetting,
  UserSetting_WebhooksSetting,
} from "@/types/proto/api/v1/user_service_pb";
import { fetchJson, parseResourceId } from "./apiClient";
import { userFromApi } from "./converters";
import type { ApiUser } from "./types";

const defaultUserGeneralSetting: UserSetting_GeneralSetting = {
  locale: "en",
  memoVisibility: "PRIVATE",
  theme: "",
};

const defaultUserWebhooksSetting: UserSetting_WebhooksSetting = {
  webhooks: [],
};

const buildUserSettings = (parent: string): UserSetting[] => {
  return [
    {
      name: `${parent}/settings/GENERAL`,
      value: { case: "generalSetting", value: defaultUserGeneralSetting },
    },
    {
      name: `${parent}/settings/WEBHOOKS`,
      value: { case: "webhooksSetting", value: defaultUserWebhooksSetting },
    },
  ];
};

export const userServiceClient = {
  async listUsers(_request?: unknown): Promise<{ users: User[]; nextPageToken: string; totalSize: number }> {
    void _request;
    const data = await fetchJson<ApiUser[]>("/users", { method: "GET" });
    const users = Array.isArray(data) ? data.map(userFromApi) : [];
    return { users, nextPageToken: "", totalSize: users.length };
  },
  async getUser(request: { name: string }): Promise<User> {
    const userId = parseResourceId(request.name);
    const data = await fetchJson<ApiUser>(`/users/${userId}`, { method: "GET" });
    return userFromApi(data);
  },
  async createUser(request: { user?: User }): Promise<User> {
    const user = request.user;
    if (!user) {
      throw new Error("Missing user payload");
    }
    const email = user.email || (user.username ? `${user.username}@example.com` : undefined);
    const payload = {
      email,
      password: user.password || "",
    };
    const data = await fetchJson<ApiUser>("/users", { method: "POST", body: payload });
    return userFromApi(data);
  },
  async updateUser(request: { user?: User }): Promise<User> {
    const user = request.user;
    if (!user?.name) {
      throw new Error("Missing user name");
    }
    const userId = parseResourceId(user.name);
    const payload = {
      email: user.email,
      nickname: user.displayName,
    };
    const data = await fetchJson<ApiUser>(`/users/${userId}`, { method: "PATCH", body: payload });
    return userFromApi(data);
  },
  async deleteUser(_request?: { name: string }): Promise<void> {
    void _request;
    return;
  },
  async getUserStats(request: { name: string; workspaceId?: string }): Promise<UserStats> {
    const userId = parseResourceId(request.name);
    const params = new URLSearchParams();
    if (request.workspaceId) {
      params.append("workspace_id", request.workspaceId);
    }
    const query = params.toString() ? `?${params.toString()}` : "";
    const data = await fetchJson<{ tagCount: Record<string, number>; memoDisplayTimestamps: string[] }>(
      `/users/${userId}/stats${query}`,
      { method: "GET" },
    );
    // Convert ISO timestamps to protobuf Timestamp format
    const timestamps = (data.memoDisplayTimestamps || []).map((ts) => {
      const date = new Date(ts);
      return { seconds: BigInt(Math.floor(date.getTime() / 1000)), nanos: 0 };
    });
    return {
      name: request.name,
      memoDisplayTimestamps: timestamps,
      memoTypeStats: {
        linkCount: 0,
        codeCount: 0,
        todoCount: 0,
        undoCount: 0,
      },
      tagCount: data.tagCount || {},
      pinnedMemos: [],
      totalMemoCount: 0,
    } as unknown as UserStats;
  },
  async listAllUserStats(_request?: unknown): Promise<{ stats: UserStats[] }> {
    void _request;
    return { stats: [] };
  },
  async listUserSettings(request: { parent: string }): Promise<{ settings: UserSetting[]; nextPageToken: string; totalSize: number }> {
    const settings = buildUserSettings(request.parent);
    return { settings, nextPageToken: "", totalSize: settings.length };
  },
  async updateUserSetting(request: { setting?: UserSetting }): Promise<UserSetting> {
    if (request.setting) {
      return request.setting;
    }
    return buildUserSettings("users/1")[0];
  },
  async listUserNotifications(request: { parent: string }): Promise<{ notifications: UserNotification[]; nextPageToken: string }> {
    const userId = parseResourceId(request.parent);
    const data = await fetchJson<{ notifications: UserNotification[] }>(
      `/users/${userId}/notifications:list`,
      { method: "POST", body: {} },
    );
    return { notifications: data.notifications || [], nextPageToken: "" };
  },
  async updateUserNotification(request: { notification?: UserNotification }): Promise<UserNotification> {
    if (!request.notification?.name) {
      throw new Error("Missing notification name");
    }
    const userId = parseResourceId(request.notification.name.split("/")[1] ? request.notification.name : "users/1/notifications/1");
    const notifId = request.notification.name.split("/").pop();
    const data = await fetchJson<UserNotification>(
      `/users/${userId}/notifications/${notifId}`,
      { method: "PATCH", body: { notification: { status: request.notification.status } } },
    );
    return data;
  },
  async deleteUserNotification(request: { name: string }): Promise<void> {
    // name format: "users/{userId}/notifications/{notifId}"
    const parts = request.name.split("/");
    const userId = parts[1] || "1";
    const notifId = parts[3] || parts[1];
    await fetchJson(`/users/${userId}/notifications/${notifId}`, { method: "DELETE" });
  },
  async listPersonalAccessTokens(_request: { parent: string }): Promise<{
    personalAccessTokens: PersonalAccessToken[];
    nextPageToken: string;
    totalSize: number;
  }> {
    void _request;
    return { personalAccessTokens: [], nextPageToken: "", totalSize: 0 };
  },
  async createPersonalAccessToken(request: {
    parent?: string;
    description?: string;
    expiresInDays?: number;
  }): Promise<CreatePersonalAccessTokenResponse> {
    const parent = request.parent || "users/1";
    const tokenId = Date.now().toString();
    const personalAccessToken: PersonalAccessToken = {
      name: `${parent}/personalAccessTokens/${tokenId}`,
      description: request.description || "",
    };
    return {
      personalAccessToken,
      token: "stub-token",
    };
  },
  async deletePersonalAccessToken(_request: { name: string }): Promise<void> {
    void _request;
    return;
  },
  async listUserWebhooks(_request: { parent: string }): Promise<{ webhooks: UserWebhook[] }> {
    void _request;
    return { webhooks: [] };
  },
  async createUserWebhook(request: { parent?: string; webhook?: UserWebhook }): Promise<UserWebhook> {
    const parent = request.parent || "users/1";
    const webhook = request.webhook;
    if (webhook?.name) {
      return webhook;
    }
    return {
      name: `${parent}/webhooks/${Date.now()}`,
      url: webhook?.url || "",
      displayName: webhook?.displayName || "",
    };
  },
  async updateUserWebhook(request: { webhook?: UserWebhook }): Promise<UserWebhook> {
    if (request.webhook) {
      return request.webhook;
    }
    return {
      name: "users/1/webhooks/1",
      url: "",
      displayName: "",
    };
  },
  async deleteUserWebhook(_request: { name: string }): Promise<void> {
    void _request;
    return;
  },
  // OpenAI API Key Management
  async getOpenAIKey(userId: string): Promise<{ has_key: boolean; masked_key: string | null }> {
    return fetchJson<{ has_key: boolean; masked_key: string | null }>(`/users/${userId}/openai-key`, {
      method: "GET",
    });
  },
  async updateOpenAIKey(userId: string, apiKey: string): Promise<{ success: boolean; message: string; masked_key: string }> {
    return fetchJson<{ success: boolean; message: string; masked_key: string }>(`/users/${userId}/openai-key`, {
      method: "PUT",
      body: { api_key: apiKey },
    });
  },
  async deleteOpenAIKey(userId: string): Promise<{ success: boolean; message: string }> {
    return fetchJson<{ success: boolean; message: string }>(`/users/${userId}/openai-key`, {
      method: "DELETE",
    });
  },
};

