// Calendly API v2 Client

import type {
  CalendlyConfig,
  CalendlyUser,
  CalendlyEvent,
  CalendlyEventType,
  CalendlyInvitee,
  CalendlyOrganization,
  CalendlyOrganizationMembership,
  CalendlyOrganizationInvitation,
  CalendlySchedulingLink,
  CalendlyWebhookSubscription,
  CalendlyAvailableTime,
  CalendlyUserBusyTime,
  CalendlyRoutingForm,
  CalendlyNoShow,
  PaginationParams,
  PaginatedResponse,
  CalendlyError,
} from '../types/index.js';

export class CalendlyClient {
  private apiKey: string;
  private baseUrl: string;

  constructor(config: CalendlyConfig) {
    this.apiKey = config.apiKey;
    this.baseUrl = config.baseUrl || 'https://api.calendly.com';
  }

  private async request<T>(
    endpoint: string,
    options: RequestInit = {}
  ): Promise<T> {
    const url = `${this.baseUrl}${endpoint}`;
    
    const headers = {
      'Authorization': `Bearer ${this.apiKey}`,
      'Content-Type': 'application/json',
      ...options.headers,
    };

    try {
      const response = await fetch(url, {
        ...options,
        headers,
      });

      if (!response.ok) {
        const errorData = await response.json().catch(() => ({}));
        const error: CalendlyError = errorData as CalendlyError;
        throw new Error(
          `Calendly API Error (${response.status}): ${error.title || 'Unknown error'} - ${error.message || response.statusText}`
        );
      }

      // Handle 204 No Content
      if (response.status === 204) {
        return {} as T;
      }

      const data: unknown = await response.json();
      return data as T;
    } catch (error) {
      if (error instanceof Error) {
        throw error;
      }
      throw new Error(`Network error: ${String(error)}`);
    }
  }

  private buildQueryString(params: Record<string, any>): string {
    const searchParams = new URLSearchParams();
    Object.entries(params).forEach(([key, value]) => {
      if (value !== undefined && value !== null) {
        searchParams.append(key, String(value));
      }
    });
    const query = searchParams.toString();
    return query ? `?${query}` : '';
  }

  // Users
  async getCurrentUser(): Promise<{ resource: CalendlyUser }> {
    return this.request('/users/me');
  }

  async getUserByUri(uri: string): Promise<{ resource: CalendlyUser }> {
    return this.request(`/users/${encodeURIComponent(uri)}`);
  }

  // Events
  async listEvents(params: {
    organization?: string;
    user?: string;
    invitee_email?: string;
    status?: 'active' | 'canceled';
    min_start_time?: string;
    max_start_time?: string;
    count?: number;
    page_token?: string;
    sort?: string;
  }): Promise<PaginatedResponse<CalendlyEvent>> {
    const query = this.buildQueryString(params);
    return this.request(`/scheduled_events${query}`);
  }

  async getEvent(uuid: string): Promise<{ resource: CalendlyEvent }> {
    return this.request(`/scheduled_events/${uuid}`);
  }

  async cancelEvent(uuid: string, reason?: string): Promise<{ resource: CalendlyEvent }> {
    return this.request(`/scheduled_events/${uuid}/cancellation`, {
      method: 'POST',
      body: JSON.stringify({ reason: reason || 'Canceled' }),
    });
  }

  // Event Invitees
  async listEventInvitees(
    eventUuid: string,
    params?: PaginationParams
  ): Promise<PaginatedResponse<CalendlyInvitee>> {
    const query = this.buildQueryString(params || {});
    return this.request(`/scheduled_events/${eventUuid}/invitees${query}`);
  }

  async getInvitee(inviteeUuid: string): Promise<{ resource: CalendlyInvitee }> {
    return this.request(`/scheduled_events/invitees/${inviteeUuid}`);
  }

  // No-shows
  async listInviteeNoShows(inviteeUri: string): Promise<PaginatedResponse<CalendlyNoShow>> {
    const query = this.buildQueryString({ invitee: inviteeUri });
    return this.request(`/invitee_no_shows${query}`);
  }

  async createInviteeNoShow(inviteeUri: string): Promise<{ resource: CalendlyNoShow }> {
    return this.request('/invitee_no_shows', {
      method: 'POST',
      body: JSON.stringify({ invitee: inviteeUri }),
    });
  }

  async deleteInviteeNoShow(noShowUuid: string): Promise<void> {
    return this.request(`/invitee_no_shows/${noShowUuid}`, {
      method: 'DELETE',
    });
  }

  // Event Types
  async listEventTypes(params: {
    organization?: string;
    user?: string;
    active?: boolean;
    count?: number;
    page_token?: string;
    sort?: string;
  }): Promise<PaginatedResponse<CalendlyEventType>> {
    const query = this.buildQueryString(params);
    return this.request(`/event_types${query}`);
  }

  async getEventType(uuid: string): Promise<{ resource: CalendlyEventType }> {
    return this.request(`/event_types/${uuid}`);
  }

  async listAvailableTimes(
    eventTypeUri: string,
    params: {
      start_time: string;
      end_time: string;
    }
  ): Promise<PaginatedResponse<CalendlyAvailableTime>> {
    const query = this.buildQueryString({
      event_type: eventTypeUri,
      ...params,
    });
    return this.request(`/event_type_available_times${query}`);
  }

  // User Availability & Busy Times
  async getUserBusyTimes(
    userUri: string,
    params: {
      start_time: string;
      end_time: string;
    }
  ): Promise<PaginatedResponse<CalendlyUserBusyTime>> {
    const query = this.buildQueryString({
      user: userUri,
      ...params,
    });
    return this.request(`/user_busy_times${query}`);
  }

  // Scheduling Links
  async createSchedulingLink(params: {
    max_event_count: number;
    owner: string;
    owner_type: 'EventType' | 'Group';
  }): Promise<{ resource: CalendlySchedulingLink }> {
    return this.request('/scheduling_links', {
      method: 'POST',
      body: JSON.stringify(params),
    });
  }

  // Organizations
  async getOrganization(uuid: string): Promise<{ resource: CalendlyOrganization }> {
    return this.request(`/organizations/${uuid}`);
  }

  async listOrganizationMemberships(
    organizationUri: string,
    params?: {
      count?: number;
      page_token?: string;
      email?: string;
    }
  ): Promise<PaginatedResponse<CalendlyOrganizationMembership>> {
    const query = this.buildQueryString({
      organization: organizationUri,
      ...params,
    });
    return this.request(`/organization_memberships${query}`);
  }

  async listOrganizationInvitations(
    organizationUri: string,
    params?: {
      count?: number;
      page_token?: string;
      email?: string;
      status?: string;
    }
  ): Promise<PaginatedResponse<CalendlyOrganizationInvitation>> {
    const query = this.buildQueryString({
      organization: organizationUri,
      ...params,
    });
    return this.request(`/organization_invitations${query}`);
  }

  async inviteUserToOrganization(
    organizationUri: string,
    email: string
  ): Promise<{ resource: CalendlyOrganizationInvitation }> {
    return this.request('/organization_invitations', {
      method: 'POST',
      body: JSON.stringify({
        organization: organizationUri,
        email,
      }),
    });
  }

  async revokeOrganizationInvitation(uuid: string): Promise<{ resource: CalendlyOrganizationInvitation }> {
    return this.request(`/organization_invitations/${uuid}`, {
      method: 'DELETE',
    });
  }

  async removeOrganizationMembership(uuid: string): Promise<void> {
    return this.request(`/organization_memberships/${uuid}`, {
      method: 'DELETE',
    });
  }

  // Routing Forms
  async listRoutingForms(
    organizationUri: string,
    params?: PaginationParams
  ): Promise<PaginatedResponse<CalendlyRoutingForm>> {
    const query = this.buildQueryString({
      organization: organizationUri,
      ...params,
    });
    return this.request(`/routing_forms${query}`);
  }

  async getRoutingForm(uuid: string): Promise<{ resource: CalendlyRoutingForm }> {
    return this.request(`/routing_forms/${uuid}`);
  }

  // Webhooks
  async listWebhookSubscriptions(
    params: {
      organization: string;
      scope: 'user' | 'organization';
      user?: string;
    } & PaginationParams
  ): Promise<PaginatedResponse<CalendlyWebhookSubscription>> {
    const query = this.buildQueryString(params);
    return this.request(`/webhook_subscriptions${query}`);
  }

  async createWebhookSubscription(params: {
    url: string;
    events: string[];
    organization: string;
    user?: string;
    scope: 'user' | 'organization';
    signing_key?: string;
  }): Promise<{ resource: CalendlyWebhookSubscription }> {
    return this.request('/webhook_subscriptions', {
      method: 'POST',
      body: JSON.stringify(params),
    });
  }

  async getWebhookSubscription(uuid: string): Promise<{ resource: CalendlyWebhookSubscription }> {
    return this.request(`/webhook_subscriptions/${uuid}`);
  }

  async deleteWebhookSubscription(uuid: string): Promise<void> {
    return this.request(`/webhook_subscriptions/${uuid}`, {
      method: 'DELETE',
    });
  }
}
