import axios from 'axios';
import type { AxiosInstance } from 'axios';
import type {
  LoginRequest,
  LoginResponse,
  RefreshResponse,
  MicrosoftLoginResponse,
  Job,
  JobCreateRequest,
  JobListResponse,
  JobDownloadsResponse,
  VttContentResponse,
  VttUpdateRequest,
  AssetValidationResponse,
  BulkDeleteRequest,
  BulkDeleteResponse,
  BulkApproveRequest,
  BulkApproveResponse,
  BulkReturnToQCRequest,
  BulkReturnToQCResponse,
  JobDeleteResponse,
  User,
  UserListResponse,
  CreateUserRequest,
  UpdateUserRequest,
  ResetPasswordResponse,
  AdminStatsResponse,
  ProviderVoicesResponse,
  LanguagesResponse,
  TTSPreferences,
  ProviderOptionsResponse,
  TTSStylePreset,
  TTSProvider,
  AccessibleVideoMethod,
  ReviewNote,
  ReviewNoteCreateRequest,
  ReviewNoteUpdateRequest,
  ReviewNotesListResponse,
  AccessibleVideoEditState,
  PausePointData,
  Client,
  Team,
  Project,
  PMUser,
  ClientCreateRequest,
  TeamCreateRequest,
  ProjectCreateRequest,
  Organization,
  Membership,
  MembershipCreate,
  MembershipUpdate,
  OrganizationCreateRequest,
  OrganizationUpdateRequest,
  Invitation,
  InvitationCreate,
  InvitationPreview,
  InvitationAcceptRequest,
  InvitationAcceptResponse,

  Glossary,
  GlossaryDetail,
  GlossaryVersion,
  GlossaryTermsResponse,
} from '../types/api';

const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || 'http://localhost:8000';

function getCsrfToken(): string | null {
  const match = document.cookie.match(/(?:^|;\s*)csrf_token=([^;]+)/);
  return match ? decodeURIComponent(match[1]) : null;
}

class ApiClient {
  private client: AxiosInstance;
  private accessToken: string | null = null;

  constructor() {
    this.client = axios.create({
      baseURL: `${API_BASE_URL}/api/v1`,
      withCredentials: true,
      timeout: 30000,
    });

    this.setupInterceptors();
  }

  private setupInterceptors() {
    // Request interceptor to add auth token
    this.client.interceptors.request.use(
      (config) => {
        if (this.accessToken) {
          config.headers.Authorization = `Bearer ${this.accessToken}`;
        }
        return config;
      },
      (error) => Promise.reject(error)
    );

    // Response interceptor to handle token refresh
    this.client.interceptors.response.use(
      (response) => response,
      async (error) => {
        const originalRequest = error.config;

        // Don't try to refresh if this is already the refresh endpoint
        if (error.response?.status === 401 && 
            !originalRequest._retry && 
            originalRequest.url !== '/auth/refresh') {
          originalRequest._retry = true;

          try {
            const csrfToken = getCsrfToken();
            const refreshResponse = await this.client.post('/auth/refresh', {}, {
              headers: csrfToken ? { 'X-CSRF-Token': csrfToken } : {},
            });
            this.accessToken = refreshResponse.data.access_token;
            
            // Retry original request with new token
            originalRequest.headers.Authorization = `Bearer ${this.accessToken}`;
            return this.client(originalRequest);
          } catch (refreshError) {
            // Refresh failed, clear token and update auth state
            this.accessToken = null;
            // Clear auth state in the store
            const { useAuthStore } = await import('./auth');
            useAuthStore.getState().logout();
            return Promise.reject(refreshError);
          }
        }

        return Promise.reject(error);
      }
    );
  }

  setAccessToken(token: string) {
    this.accessToken = token;
  }

  clearAccessToken() {
    this.accessToken = null;
  }

  getAccessToken(): string | null {
    return this.accessToken;
  }

  // Auth endpoints
  async login(credentials: LoginRequest): Promise<LoginResponse> {
    const response = await this.client.post('/auth/login', credentials);
    this.setAccessToken(response.data.access_token);
    return response.data;
  }

  async loginWithMicrosoft(idToken: string): Promise<MicrosoftLoginResponse> {
    const response = await this.client.post('/auth/microsoft', { id_token: idToken });
    this.setAccessToken(response.data.access_token);
    return response.data;
  }

  async refresh(): Promise<RefreshResponse> {
    const csrfToken = getCsrfToken();
    const response = await this.client.post('/auth/refresh', {}, {
      headers: csrfToken ? { 'X-CSRF-Token': csrfToken } : {},
    });
    this.setAccessToken(response.data.access_token);
    return response.data;
  }

  async logout(): Promise<void> {
    await this.client.post('/auth/logout');
    this.clearAccessToken();
  }

  // Job endpoints
  async getJobs(filters?: { status?: string; mine?: boolean; page?: number; size?: number }): Promise<JobListResponse> {
    const params = new URLSearchParams();
    if (filters?.status) params.append('status', filters.status);
    if (filters?.mine) params.append('mine', 'true');
    if (filters?.page) params.append('page', filters.page.toString());
    if (filters?.size) params.append('size', filters.size.toString());

    const response = await this.client.get(`/jobs?${params.toString()}`);
    return response.data;
  }

  async getJob(id: string): Promise<Job> {
    const response = await this.client.get(`/jobs/${id}`);
    return response.data;
  }

  async createJob(data: JobCreateRequest, file: File, onUploadProgress?: (progressEvent: { loaded: number; total: number }) => void): Promise<Job> {
    const formData = new FormData();
    formData.append('title', data.title);
    formData.append('requested_outputs', JSON.stringify(data.requested_outputs));
    if (data.brand_context) {
      formData.append('brand_context', data.brand_context);
    }
    if (data.project_id) {
      formData.append('project_id', data.project_id);
    }
    if (data.deadline) {
      formData.append('deadline', data.deadline);
    }
    if (data.initial_linguist_id) {
      formData.append('initial_linguist_id', data.initial_linguist_id);
    }
    if (data.initial_reviewer_id) {
      formData.append('initial_reviewer_id', data.initial_reviewer_id);
    }
    if (data.brief_id) {
      formData.append('brief_id', data.brief_id);
    }
    formData.append('file', file);

    const response = await this.client.post('/jobs', formData, {
      headers: {
        'Content-Type': 'multipart/form-data',
      },
      timeout: 0, // No timeout for video uploads (can be large files)
      onUploadProgress: onUploadProgress ? (progressEvent) => {
        if (progressEvent.total) {
          onUploadProgress({
            loaded: progressEvent.loaded,
            total: progressEvent.total
          });
        }
      } : undefined,
    });
    return response.data;
  }

  async updateJob(id: string, data: Partial<Job>): Promise<Job> {
    const response = await this.client.patch(`/jobs/${id}`, data);
    return response.data;
  }

  async approveEnglish(id: string, notes?: string): Promise<Job> {
    // Legacy method - calls approve_source for backwards compatibility
    return this.approveSource(id, notes);
  }

  async approveSource(
    id: string,
    notes?: string,
    tts_preferences?: TTSPreferences,
    accessible_video_method?: AccessibleVideoMethod
  ): Promise<Job> {
    const response = await this.client.post(`/jobs/${id}/actions/approve_source`, {
      notes,
      tts_preferences,
      accessible_video_method
    });
    return response.data;
  }

  async rejectJob(id: string, notes: string): Promise<Job> {
    const response = await this.client.post(`/jobs/${id}/actions/reject`, { notes });
    return response.data;
  }

  async completeJob(id: string, notes?: string): Promise<Job> {
    const response = await this.client.post(`/jobs/${id}/actions/complete`, { notes });
    return response.data;
  }

  async rejectFinalReview(id: string, notes: string): Promise<Job> {
    const response = await this.client.post(`/jobs/${id}/actions/reject_final`, { notes });
    return response.data;
  }

  async updateTTSPreferences(id: string, tts_preferences: TTSPreferences): Promise<Job> {
    const response = await this.client.put(`/jobs/${id}/tts-preferences`, {
      tts_preferences
    });
    return response.data;
  }

  async getJobDownloads(id: string): Promise<JobDownloadsResponse> {
    const response = await this.client.get(`/jobs/${id}/downloads`);
    return response.data;
  }

  async getJobVttContent(id: string, language?: string): Promise<VttContentResponse> {
    const params = language ? `?language=${language}` : '';
    const response = await this.client.get(`/jobs/${id}/vtt${params}`);
    return response.data;
  }

  async updateJobVttContent(id: string, data: VttUpdateRequest): Promise<Job> {
    const response = await this.client.patch(`/jobs/${id}/vtt`, data);
    return response.data;
  }

  async adjustVttTiming(id: string, data: {
    offset_seconds: number;
    language?: string;
    adjust_captions?: boolean;
    adjust_audio_description?: boolean;
  }): Promise<Job> {
    const response = await this.client.post(`/jobs/${id}/vtt/adjust-timing`, data);
    return response.data;
  }

  async retranslateLanguage(id: string, language: string, reason?: string): Promise<Job> {
    const response = await this.client.post(`/jobs/${id}/retranslate-language`, { language, reason });
    return response.data;
  }

  async validateJobAssets(id: string): Promise<AssetValidationResponse> {
    const response = await this.client.get(`/jobs/${id}/validate`);
    return response.data;
  }

  async deleteJob(id: string): Promise<JobDeleteResponse> {
    const response = await this.client.delete(`/jobs/${id}`);
    return response.data;
  }

  async cloneJob(id: string): Promise<Job> {
    const response = await this.client.post(`/jobs/${id}/clone`);
    return response.data;
  }

  async bulkDeleteJobs(data: BulkDeleteRequest): Promise<BulkDeleteResponse> {
    const response = await this.client.delete('/jobs/bulk', { data });
    return response.data;
  }

  async bulkApproveJobs(data: BulkApproveRequest): Promise<BulkApproveResponse> {
    const response = await this.client.post('/jobs/bulk/approve', data);
    return response.data;
  }

  async bulkDownloadJobs(jobIds: string[]): Promise<Blob> {
    const response = await this.client.post(
      '/jobs/bulk/download',
      { job_ids: jobIds },
      {
        responseType: 'blob',
        timeout: 0, // No timeout for large downloads
      }
    );
    return response.data;
  }

  async reprocessJob(id: string): Promise<{ message: string }> {
    const response = await this.client.post(`/admin/maintenance/reprocess-job/${id}`);
    return response.data;
  }

  async retryTts(id: string): Promise<Job> {
    const response = await this.client.post(`/jobs/${id}/actions/retry_tts`);
    return response.data;
  }

  async cancelJob(id: string): Promise<Job> {
    const response = await this.client.post(`/jobs/${id}/cancel`);
    return response.data;
  }

  async retryJob(id: string, fromStep?: string): Promise<Job> {
    const params = fromStep ? { from_step: fromStep } : {};
    const response = await this.client.post(`/jobs/${id}/retry`, null, { params });
    return response.data;
  }

  async returnToQC(id: string, data: { notes: string }): Promise<Job> {
    const response = await this.client.post(`/jobs/${id}/actions/return_to_qc`, data);
    return response.data;
  }

  async bulkReturnToQC(data: BulkReturnToQCRequest): Promise<BulkReturnToQCResponse> {
    const response = await this.client.post('/jobs/bulk/return-to-qc', data);
    return response.data;
  }

  async listFailures(filters?: { step?: string; org_id?: string; limit?: number; skip?: number }): Promise<Job[]> {
    const params: Record<string, string> = {};
    if (filters?.step) params.step = filters.step;
    if (filters?.org_id) params.org_id = filters.org_id;
    if (filters?.limit != null) params.limit = String(filters.limit);
    if (filters?.skip != null) params.skip = String(filters.skip);
    const response = await this.client.get('/admin/production/failures', { params });
    return response.data;
  }

  async bulkRetry(job_ids: string[], strategy: 'auto' | 'from_scratch' = 'auto') {
    const response = await this.client.post('/admin/production/bulk-retry', { job_ids, strategy });
    return response.data as { retried: string[]; skipped: string[]; errors: Array<{ job_id: string; error: string }> };
  }

  async listBriefs(): Promise<import('../types/api').JobBriefResponse[]> {
    const response = await this.client.get('/briefs');
    return response.data;
  }

  async listBriefAssignees(): Promise<import('../types/api').User[]> {
    const response = await this.client.get('/admin/brief-assignees');
    return response.data;
  }

  async createBrief(data: import('../types/api').JobBriefCreate): Promise<import('../types/api').JobBriefResponse> {
    const response = await this.client.post('/briefs', data);
    return response.data;
  }

  async getBrief(id: string): Promise<import('../types/api').JobBriefResponse> {
    const response = await this.client.get(`/briefs/${id}`);
    return response.data;
  }

  async submitBrief(id: string): Promise<import('../types/api').JobBriefResponse> {
    const response = await this.client.post(`/briefs/${id}/submit`);
    return response.data;
  }

  async approveBrief(id: string): Promise<import('../types/api').JobBriefResponse> {
    const response = await this.client.post(`/briefs/${id}/approve`);
    return response.data;
  }

  // User Management endpoints
  async listUsers(filters?: {
    page?: number;
    size?: number;
    role?: string;
    active_only?: boolean;
    org_id?: string;
  }): Promise<UserListResponse> {
    const params = new URLSearchParams();
    if (filters?.page) params.append('page', filters.page.toString());
    if (filters?.size) params.append('size', filters.size.toString());
    if (filters?.role) params.append('role', filters.role);
    if (filters?.active_only !== undefined) params.append('active_only', filters.active_only.toString());
    if (filters?.org_id) params.append('org_id', filters.org_id);

    const response = await this.client.get(`/admin/users?${params.toString()}`);
    return response.data;
  }

  async getUser(userId: string): Promise<User> {
    const response = await this.client.get(`/admin/users/${userId}`);
    return response.data;
  }

  async createUser(data: CreateUserRequest): Promise<User> {
    const response = await this.client.post('/admin/users', data);
    return response.data;
  }

  async updateUser(userId: string, data: UpdateUserRequest): Promise<User> {
    const response = await this.client.patch(`/admin/users/${userId}`, data);
    return response.data;
  }

  async deactivateUser(userId: string): Promise<{ message: string }> {
    const response = await this.client.delete(`/admin/users/${userId}`);
    return response.data;
  }

  async resetUserPassword(userId: string): Promise<ResetPasswordResponse> {
    const response = await this.client.post(`/admin/users/${userId}/password/reset`);
    return response.data;
  }

  async getAdminStats(): Promise<AdminStatsResponse> {
    const response = await this.client.get('/admin/stats');
    return response.data;
  }

  // TTS endpoints
  async getVoices(provider: TTSProvider = 'gemini'): Promise<ProviderVoicesResponse> {
    const response = await this.client.get(`/tts/voices?provider=${provider}`);
    return response.data;
  }

  async getLanguages(): Promise<LanguagesResponse> {
    const response = await this.client.get('/tts/languages');
    return response.data;
  }

  async getTTSOptions(provider: TTSProvider = 'gemini'): Promise<ProviderOptionsResponse> {
    const response = await this.client.get(`/tts/options?provider=${provider}`);
    return response.data;
  }

  async previewVoice(
    voiceName: string,
    language: string,
    model?: string,
    speed?: number,
    stylePreset?: TTSStylePreset,
    customStylePrompt?: string,
    provider?: TTSProvider,
    stability?: number,
    similarityBoost?: number,
  ): Promise<Blob> {
    try {
      const response = await this.client.post(
        '/tts/preview',
        {
          voice_name: voiceName,
          language,
          provider: provider || 'gemini',
          model: model || 'flash',
          speed: speed || 1.0,
          style_preset: stylePreset || 'neutral',
          custom_style_prompt: customStylePrompt,
          stability: stability,
          similarity_boost: similarityBoost,
        },
        { responseType: 'blob' }
      );
      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response?.data instanceof Blob) {
        const text = await error.response.data.text();
        try {
          const json = JSON.parse(text);
          throw new Error(json.detail || 'Failed to generate preview');
        } catch {
          throw new Error(text || 'Failed to generate preview');
        }
      }
      throw error;
    }
  }

  // Review Notes endpoints
  async getReviewNotes(jobId: string, assetKey?: string): Promise<ReviewNotesListResponse> {
    const params = assetKey ? `?asset_key=${encodeURIComponent(assetKey)}` : '';
    const response = await this.client.get(`/jobs/${jobId}/review-notes${params}`);
    return response.data;
  }

  async createReviewNote(jobId: string, data: ReviewNoteCreateRequest): Promise<ReviewNote> {
    const response = await this.client.post(`/jobs/${jobId}/review-notes`, data);
    return response.data;
  }

  async updateReviewNote(jobId: string, noteId: string, data: ReviewNoteUpdateRequest): Promise<ReviewNote> {
    const response = await this.client.patch(`/jobs/${jobId}/review-notes/${noteId}`, data);
    return response.data;
  }

  async deleteReviewNote(jobId: string, noteId: string): Promise<void> {
    await this.client.delete(`/jobs/${jobId}/review-notes/${noteId}`);
  }

  // Accessible Video QC Editing endpoints
  async getAccessibleVideoEditState(jobId: string, language: string): Promise<AccessibleVideoEditState | null> {
    try {
      const response = await this.client.get(`/jobs/${jobId}/accessible-video/${language}/edit-state`);
      return response.data;
    } catch (err) {
      const e = err as { response?: { status?: number } };
      if (e?.response?.status === 404) return null;
      throw err;
    }
  }

  async updatePausePoint(
    jobId: string,
    language: string,
    cueIndex: number,
    adjustedMs: number
  ): Promise<PausePointData> {
    const response = await this.client.patch(
      `/jobs/${jobId}/accessible-video/${language}/pause-points/${cueIndex}`,
      { adjusted_ms: adjustedMs }
    );
    return response.data;
  }

  async queueTTSRegeneration(
    jobId: string,
    language: string,
    cueIndices: number[]
  ): Promise<{ message: string; queued_cues: number[] }> {
    const response = await this.client.post(
      `/jobs/${jobId}/accessible-video/${language}/tts-regeneration`,
      { cue_indices: cueIndices }
    );
    return response.data;
  }

  async removeTTSRegeneration(
    jobId: string,
    language: string,
    cueIndex: number
  ): Promise<{ message: string }> {
    const response = await this.client.delete(
      `/jobs/${jobId}/accessible-video/${language}/tts-regeneration/${cueIndex}`
    );
    return response.data;
  }

  async rerenderAccessibleVideo(
    jobId: string,
    language: string,
    whisperRefine: boolean = false
  ): Promise<Job> {
    const response = await this.client.post(
      `/jobs/${jobId}/accessible-video/${language}/re-render`,
      { whisper_refine: whisperRefine }
    );
    return response.data;
  }

  // ── Client / Team / Project ──────────────────────────────────────────────

  async listClients(): Promise<Client[]> {
    const r = await this.client.get('/clients');
    return r.data;
  }

  async createClient(data: ClientCreateRequest): Promise<Client> {
    const r = await this.client.post('/clients', data);
    return r.data;
  }

  async updateClient(clientId: string, data: Partial<ClientCreateRequest & { is_active: boolean }>): Promise<Client> {
    const r = await this.client.patch(`/clients/${clientId}`, data);
    return r.data;
  }

  async getClient(clientId: string): Promise<Client> {
    const r = await this.client.get(`/clients/${clientId}`);
    return r.data;
  }

  async listPMs(clientId: string): Promise<PMUser[]> {
    const r = await this.client.get(`/clients/${clientId}/pm`);
    return r.data;
  }

  async assignPM(clientId: string, userId: string): Promise<void> {
    await this.client.post(`/clients/${clientId}/pm`, { user_id: userId });
  }

  async removePM(clientId: string, userId: string): Promise<void> {
    await this.client.delete(`/clients/${clientId}/pm/${userId}`);
  }

  async listTeams(clientId: string): Promise<Team[]> {
    const r = await this.client.get(`/clients/${clientId}/teams`);
    return r.data;
  }

  async createTeam(clientId: string, data: TeamCreateRequest): Promise<Team> {
    const r = await this.client.post(`/clients/${clientId}/teams`, data);
    return r.data;
  }

  async updateTeam(clientId: string, teamId: string, name: string): Promise<Team> {
    const r = await this.client.patch(`/clients/${clientId}/teams/${teamId}`, { name });
    return r.data;
  }

  async deleteTeam(clientId: string, teamId: string): Promise<void> {
    await this.client.delete(`/clients/${clientId}/teams/${teamId}`);
  }

  async addTeamMember(clientId: string, teamId: string, userId: string): Promise<void> {
    await this.client.post(`/clients/${clientId}/teams/${teamId}/members`, { user_id: userId });
  }

  async removeTeamMember(clientId: string, teamId: string, userId: string): Promise<void> {
    await this.client.delete(`/clients/${clientId}/teams/${teamId}/members/${userId}`);
  }

  async listProjects(clientId: string): Promise<Project[]> {
    const r = await this.client.get(`/clients/${clientId}/projects`);
    return r.data;
  }

  async listAllProjects(): Promise<Project[]> {
    const r = await this.client.get('/clients/all-projects');
    return r.data;
  }

  async createProject(clientId: string, data: ProjectCreateRequest): Promise<Project> {
    const r = await this.client.post(`/clients/${clientId}/projects`, data);
    return r.data;
  }

  async updateProject(clientId: string, projectId: string, data: Partial<{ name: string; is_active: boolean }>): Promise<Project> {
    const r = await this.client.patch(`/clients/${clientId}/projects/${projectId}`, data);
    return r.data;
  }

  async archiveProject(clientId: string, projectId: string): Promise<void> {
    await this.client.delete(`/clients/${clientId}/projects/${projectId}`);
  }

  // ── Organizations (SaaS) ──────────────────────────────────────────────────

  async listOrganizations(): Promise<Organization[]> {
    const r = await this.client.get('/organizations');
    return r.data;
  }

  async getOrganization(orgId: string): Promise<Organization> {
    const r = await this.client.get(`/organizations/${orgId}`);
    return r.data;
  }

  async createOrganization(data: OrganizationCreateRequest): Promise<Organization> {
    const r = await this.client.post('/organizations', data);
    return r.data;
  }

  async updateOrganization(orgId: string, data: OrganizationUpdateRequest): Promise<Organization> {
    const r = await this.client.patch(`/organizations/${orgId}`, data);
    return r.data;
  }

  async listOrgMembers(orgId: string): Promise<Membership[]> {
    const r = await this.client.get(`/organizations/${orgId}/members`);
    return r.data;
  }

  async addOrgMember(orgId: string, data: MembershipCreate): Promise<Membership> {
    const r = await this.client.post(`/organizations/${orgId}/members`, data);
    return r.data;
  }

  async updateOrgMember(orgId: string, userId: string, data: MembershipUpdate): Promise<Membership> {
    const r = await this.client.patch(`/organizations/${orgId}/members/${userId}`, data);
    return r.data;
  }

  async removeOrgMember(orgId: string, userId: string): Promise<void> {
    await this.client.delete(`/organizations/${orgId}/members/${userId}`);
  }

  async getMyMemberships(): Promise<Membership[]> {
    const r = await this.client.get('/organizations/me/memberships');
    return r.data;
  }

  // ── Invitations ───────────────────────────────────────────────────────────

  async listInvitations(orgId: string): Promise<Invitation[]> {
    const r = await this.client.get(`/organizations/${orgId}/invitations`);
    return r.data;
  }

  async createInvitation(orgId: string, data: InvitationCreate): Promise<Invitation> {
    const r = await this.client.post(`/organizations/${orgId}/invitations`, data);
    return r.data;
  }

  async revokeInvitation(orgId: string, invitationId: string): Promise<void> {
    await this.client.delete(`/organizations/${orgId}/invitations/${invitationId}`);
  }

  async previewInvitation(token: string): Promise<InvitationPreview> {
    const r = await this.client.post('/invitations/preview', { token });
    return r.data;
  }

  async acceptInvitation(data: InvitationAcceptRequest): Promise<InvitationAcceptResponse> {
    const r = await this.client.post('/invitations/accept', data);
    return r.data;
  }

  // ── VTT Versions ─────────────────────────────────────────────────────────

  async listVttVersions(jobId: string, lang: string, kind: import('../types/api').VttKind, skip = 0, limit = 50): Promise<import('../types/api').VttVersionListResponse> {
    const r = await this.client.get(`/jobs/${jobId}/vtt/versions?lang=${lang}&kind=${kind}&skip=${skip}&limit=${limit}`);
    return r.data;
  }

  async getVttVersion(jobId: string, lang: string, kind: import('../types/api').VttKind, version: number): Promise<import('../types/api').VttVersionFull> {
    const r = await this.client.get(`/jobs/${jobId}/vtt/versions/${version}?lang=${lang}&kind=${kind}`);
    return r.data;
  }

  async diffVttVersions(jobId: string, lang: string, kind: import('../types/api').VttKind, from: number, to: number): Promise<import('../types/api').VttDiffResponse> {
    const r = await this.client.get(`/jobs/${jobId}/vtt/versions/diff?lang=${lang}&kind=${kind}&from=${from}&to=${to}`);
    return r.data;
  }

  async restoreVttVersion(jobId: string, lang: string, kind: import('../types/api').VttKind, version: number): Promise<import('../types/api').VttVersionSummary> {
    const r = await this.client.post(`/jobs/${jobId}/vtt/versions/${version}/restore?lang=${lang}&kind=${kind}`);
    return r.data;
  }

  // ── Audit Logs ────────────────────────────────────────────────────────────

  async getAuditLogs(query: import('../types/api').AuditLogQuery = {}): Promise<import('../types/api').AuditLogListResponse> {
    const params = new URLSearchParams();
    if (query.action) params.append('action', query.action);
    if (query.severity) params.append('severity', query.severity);
    if (query.user_id) params.append('user_id', query.user_id);
    if (query.user_email) params.append('user_email', query.user_email);
    if (query.resource_type) params.append('resource_type', query.resource_type);
    if (query.resource_id) params.append('resource_id', query.resource_id);
    if (query.success !== undefined) params.append('success', String(query.success));
    if (query.search) params.append('search', query.search);
    if (query.start_date) params.append('start_date', query.start_date);
    if (query.end_date) params.append('end_date', query.end_date);
    if (query.skip !== undefined) params.append('skip', String(query.skip));
    if (query.limit !== undefined) params.append('limit', String(query.limit));
    if (query.sort_by) params.append('sort_by', query.sort_by);
    if (query.sort_order !== undefined) params.append('sort_order', String(query.sort_order));
    const r = await this.client.get(`/admin/audit-logs?${params.toString()}`);
    return r.data;
  }

  async getUserAuditLogs(userId: string, days = 30): Promise<import('../types/api').AuditLogEntry[]> {
    const r = await this.client.get(`/admin/audit-logs/user/${userId}?days=${days}`);
    return r.data;
  }

  async getSecurityEvents(hours = 24): Promise<import('../types/api').AuditLogEntry[]> {
    const r = await this.client.get(`/admin/audit-logs/security?hours=${hours}`);
    return r.data;
  }

  // ── Per-language QC ────────────────────────────────────────────────────────

  async getLanguageQC(jobId: string): Promise<import('../types/api').LanguageQCMapResponse> {
    const r = await this.client.get(`/jobs/${jobId}/language-qc`);
    return r.data;
  }

  async assignLanguageQC(jobId: string, lang: string, linguistUserId: string, notes?: string, deadline?: string): Promise<import('../types/api').LanguageQCStateResponse> {
    const r = await this.client.post(`/jobs/${jobId}/languages/${lang}/assign`, { linguist_user_id: linguistUserId, notes, deadline });
    return r.data;
  }

  async reassignLanguageQC(jobId: string, lang: string, linguistUserId: string, notes?: string, deadline?: string): Promise<import('../types/api').LanguageQCStateResponse> {
    const r = await this.client.post(`/jobs/${jobId}/languages/${lang}/reassign`, { linguist_user_id: linguistUserId, notes, deadline });
    return r.data;
  }

  async assignReviewerQC(jobId: string, lang: string, reviewerUserId: string, notes?: string, deadline?: string): Promise<import('../types/api').LanguageQCStateResponse> {
    const r = await this.client.post(`/jobs/${jobId}/languages/${lang}/assign-reviewer`, { reviewer_user_id: reviewerUserId, notes, deadline });
    return r.data;
  }

  async reassignReviewerQC(jobId: string, lang: string, reviewerUserId: string, notes?: string, deadline?: string): Promise<import('../types/api').LanguageQCStateResponse> {
    const r = await this.client.post(`/jobs/${jobId}/languages/${lang}/reassign-reviewer`, { reviewer_user_id: reviewerUserId, notes, deadline });
    return r.data;
  }

  async startLinguistWork(jobId: string, lang: string): Promise<import('../types/api').LanguageQCStateResponse> {
    const r = await this.client.post(`/jobs/${jobId}/languages/${lang}/start-work`);
    return r.data;
  }

  async submitForReview(jobId: string, lang: string): Promise<import('../types/api').LanguageQCStateResponse> {
    const r = await this.client.post(`/jobs/${jobId}/languages/${lang}/submit`);
    return r.data;
  }

  async openReview(jobId: string, lang: string): Promise<import('../types/api').LanguageQCStateResponse> {
    const r = await this.client.post(`/jobs/${jobId}/languages/${lang}/open-review`);
    return r.data;
  }

  async approveLanguageQC(jobId: string, lang: string, notes?: string): Promise<import('../types/api').LanguageQCStateResponse> {
    const r = await this.client.post(`/jobs/${jobId}/languages/${lang}/approve`, { notes });
    return r.data;
  }

  async rejectLanguageQC(jobId: string, lang: string, notes: string, category?: string): Promise<import('../types/api').LanguageQCStateResponse> {
    const r = await this.client.post(`/jobs/${jobId}/languages/${lang}/reject`, { notes, category: category || undefined });
    return r.data;
  }

  async markCueReviewed(jobId: string, lang: string, totalCues?: number): Promise<import('../types/api').LanguageQCStateResponse> {
    const r = await this.client.post(`/jobs/${jobId}/languages/${lang}/mark-cue-reviewed`, { total_cues: totalCues });
    return r.data;
  }

  async bulkAssignLanguages(jobId: string, payload: {
    linguist_user_id: string;
    reviewer_user_id?: string;
    languages?: string[];
    only_unassigned?: boolean;
    deadline?: string;
  }): Promise<{ assigned: string[]; skipped: string[]; errors: Record<string, string> }> {
    const r = await this.client.post(`/jobs/${jobId}/languages/bulk-assign`, payload);
    return r.data;
  }

  async reopenLanguageQC(jobId: string, lang: string, notes?: string): Promise<import('../types/api').LanguageQCStateResponse> {
    const r = await this.client.post(`/jobs/${jobId}/languages/${lang}/reopen`, { notes });
    return r.data;
  }

  async addQCComment(jobId: string, lang: string, body: string): Promise<import('../types/api').LanguageQCComment> {
    const r = await this.client.post(`/jobs/${jobId}/languages/${lang}/comments`, { body });
    return r.data;
  }

  async listQCComments(jobId: string, lang: string): Promise<import('../types/api').LanguageQCComment[]> {
    const r = await this.client.get(`/jobs/${jobId}/languages/${lang}/comments`);
    return r.data;
  }

  async getMyLanguageQCQueue(role: 'linguist' | 'reviewer' = 'linguist', statusFilter?: string, skip = 0, limit = 50): Promise<import('../types/api').QueueResponse> {
    const params = new URLSearchParams({ role });
    if (statusFilter) params.append('qc_status', statusFilter);
    params.append('skip', String(skip));
    params.append('limit', String(limit));
    const r = await this.client.get(`/me/language-qc-queue?${params.toString()}`);
    return r.data;
  }

  // ── Glossary endpoints ──────────────────────────────────────────────────────

  async getGlossaries(clientId: string): Promise<Glossary[]> {
    const r = await this.client.get(`/clients/${clientId}/glossaries`);
    return r.data;
  }

  async getGlossary(clientId: string, glossaryId: string): Promise<GlossaryDetail> {
    const r = await this.client.get(`/clients/${clientId}/glossaries/${glossaryId}`);
    return r.data;
  }

  async uploadGlossary(
    clientId: string,
    file: File,
    name: string,
    sourceLocale: string,
    sourceLocaleCol: string,
    description?: string,
    changeNote?: string,
  ): Promise<GlossaryDetail> {
    const form = new FormData();
    form.append('file', file);
    form.append('name', name);
    form.append('source_locale', sourceLocale);
    form.append('source_locale_col', sourceLocaleCol);
    if (description) form.append('description', description);
    if (changeNote) form.append('change_note', changeNote);
    const r = await this.client.post(`/clients/${clientId}/glossaries`, form, {
      headers: { 'Content-Type': 'multipart/form-data' },
      timeout: 120000,
    });
    return r.data;
  }

  async uploadGlossaryVersion(
    clientId: string,
    glossaryId: string,
    file: File,
    sourceLocaleCol: string,
    changeNote?: string,
  ): Promise<GlossaryVersion> {
    const form = new FormData();
    form.append('file', file);
    form.append('source_locale_col', sourceLocaleCol);
    if (changeNote) form.append('change_note', changeNote);
    const r = await this.client.post(`/clients/${clientId}/glossaries/${glossaryId}/versions`, form, {
      headers: { 'Content-Type': 'multipart/form-data' },
      timeout: 120000,
    });
    return r.data;
  }

  async activateGlossaryVersion(clientId: string, glossaryId: string, versionId: string): Promise<{ status: string; active_version_id: string }> {
    const form = new FormData();
    form.append('version_id', versionId);
    const r = await this.client.post(`/clients/${clientId}/glossaries/${glossaryId}/activate`, form);
    return r.data;
  }

  async reembedGlossaryVersion(clientId: string, glossaryId: string, versionId: string): Promise<{ status: string; version_id: string }> {
    const r = await this.client.post(`/clients/${clientId}/glossaries/${glossaryId}/versions/${versionId}/reembed`);
    return r.data;
  }

  async getGlossaryTerms(
    clientId: string,
    glossaryId: string,
    opts?: { versionId?: string; search?: string; page?: number; pageSize?: number },
  ): Promise<GlossaryTermsResponse> {
    const params = new URLSearchParams();
    if (opts?.versionId) params.append('version_id', opts.versionId);
    if (opts?.search) params.append('search', opts.search);
    if (opts?.page) params.append('page', String(opts.page));
    if (opts?.pageSize) params.append('page_size', String(opts.pageSize));
    const r = await this.client.get(`/clients/${clientId}/glossaries/${glossaryId}/terms?${params.toString()}`);
    return r.data;
  }

  async archiveGlossary(clientId: string, glossaryId: string): Promise<void> {
    await this.client.delete(`/clients/${clientId}/glossaries/${glossaryId}`);
  }

  // ── Share tokens ────────────────────────────────────────────────────────────

  async createShareToken(jobId: string, opts?: { expires_in_days?: number; label?: string }): Promise<{
    id: string; job_id: string; created_by_email: string; created_at: string;
    expires_at?: string; is_active: boolean; label?: string; share_url: string;
  }> {
    const r = await this.client.post(`/jobs/${jobId}/share`, opts ?? { expires_in_days: 30 });
    return r.data;
  }

  async listShareTokens(jobId: string): Promise<{ tokens: Array<{
    id: string; job_id: string; created_by_email: string; created_at: string;
    expires_at?: string; is_active: boolean; label?: string; share_url: string;
  }> }> {
    const r = await this.client.get(`/jobs/${jobId}/share`);
    return r.data;
  }

  async revokeShareToken(jobId: string, tokenId: string): Promise<void> {
    await this.client.delete(`/jobs/${jobId}/share/${tokenId}`);
  }

  async getPublicJobPreview(token: string): Promise<{
    job_id: string; job_title: string; job_status: string;
    source_language: string; languages: string[];
    language_outputs: Record<string, {
      captions_vtt_url?: string;
      audio_description_vtt_url?: string;
      accessible_video_mp4_url?: string;
      audio_description_mp3_url?: string;
    }>;
  }> {
    const r = await this.client.get(`/public/share/${token}`);
    return r.data;
  }

  async submitShareDecision(token: string, data: {
    action: 'approve' | 'reject';
    notes?: string;
    client_name?: string;
  }): Promise<{ status: string; new_job_status: string }> {
    const r = await this.client.post(`/public/share/${token}/decision`, data);
    return r.data;
  }

  // ── Production admin ────────────────────────────────────────────────────────

  async getProductionQueueStats(): Promise<{ queues: Record<string, number>; total_pending: number }> {
    const r = await this.client.get('/admin/production/queue-stats');
    return r.data;
  }

  async uploadFinalVtt(
    jobId: string,
    language: string,
    vttFile: File,
    vttType: 'captions' | 'ad' = 'captions',
  ): Promise<{ status: string; gcs_uri: string; job_status: string }> {
    const form = new FormData();
    form.append('language', language);
    form.append('vtt_type', vttType);
    form.append('vtt_file', vttFile);
    const r = await this.client.post(`/admin/production/jobs/${jobId}/upload-final-vtt`, form);
    return r.data;
  }

  // ── PR-3: Chunked / resumable upload ─────────────────────────────────────────

  async initChunkedUpload(filename: string, contentType: string, fileSize: number): Promise<{ job_id: string; upload_url: string }> {
    const r = await this.client.post('/jobs/upload/init', { filename, content_type: contentType, file_size: fileSize });
    return r.data;
  }

  async completeChunkedUpload(data: {
    job_id: string;
    title: string;
    original_filename: string;
    requested_outputs: Record<string, unknown>;
    brand_context?: string;
    project_id?: string;
    brief_id?: string;
    deadline?: string;
    initial_linguist_id?: string;
    initial_reviewer_id?: string;
  }): Promise<import('../types/api').Job> {
    const r = await this.client.post('/jobs/upload/complete', data);
    return r.data;
  }
}

export const apiClient = new ApiClient();
export const api = apiClient;