import type { Customer } from '../billing/middleware.js';
import type { OAuthCredentials } from '../multitenancy/credential-store.js';
import { createToolAudit } from '../multitenancy/audit-log.js';

const TIKTOK_API_BASE = 'https://open.tiktokapis.com/v2';

function getEnvToken(account: string): string {
  const envKey = `TIKTOK_${account.toUpperCase()}_ACCESS_TOKEN`;
  return process.env[envKey] ?? '';
}

async function resolveToken(args: { account?: string }, customer?: Customer): Promise<string> {
  if (customer) {
    const creds = await customer.getCredential<OAuthCredentials>('tiktok');
    if (!creds) throw new Error('TikTok not connected for this account');
    return creds.accessToken;
  }
  const token = getEnvToken(args.account ?? 'default');
  if (!token) throw new Error('Missing TikTok credentials. Set TIKTOK_{ACCOUNT}_ACCESS_TOKEN');
  return token;
}

async function tiktokRequest(
  endpoint: string,
  accessToken: string,
  method: 'GET' | 'POST' = 'GET',
  body?: unknown,
  params?: Record<string, string>
) {
  const url = new URL(`${TIKTOK_API_BASE}${endpoint}`);
  if (params) {
    Object.entries(params).forEach(([k, v]) => url.searchParams.set(k, v));
  }

  const res = await fetch(url.toString(), {
    method,
    headers: {
      'Authorization': `Bearer ${accessToken}`,
      'Content-Type': 'application/json',
    },
    body: body ? JSON.stringify(body) : undefined,
    signal: AbortSignal.timeout(15000),
  });

  const data = await res.json();
  if (data.error?.code && data.error.code !== 'ok') {
    throw new Error(`TikTok API error: ${data.error.message ?? data.error.code}`);
  }
  return data.data ?? data;
}

export async function getUserProfile(
  args: { account?: string },
  customer?: Customer
): Promise<{
  open_id: string;
  display_name: string;
  avatar_url?: string;
  bio?: string;
  is_verified: boolean;
  follower_count: number;
  following_count: number;
  likes_count: number;
  video_count: number;
}> {
  const accessToken = await resolveToken(args, customer);

  const fields = 'open_id,union_id,avatar_url,display_name,bio_description,is_verified,follower_count,following_count,likes_count,video_count';
  const data = await tiktokRequest('/user/info/', accessToken, 'GET', undefined, { fields });
  const u = data.user ?? data;

  return {
    open_id: u.open_id ?? '',
    display_name: u.display_name ?? '',
    avatar_url: u.avatar_url,
    bio: u.bio_description,
    is_verified: u.is_verified ?? false,
    follower_count: u.follower_count ?? 0,
    following_count: u.following_count ?? 0,
    likes_count: u.likes_count ?? 0,
    video_count: u.video_count ?? 0,
  };
}

export async function getUserVideos(
  args: { max_count?: number; account?: string },
  customer?: Customer
): Promise<Array<{
  id: string;
  title?: string;
  video_description?: string;
  duration: number;
  cover_image_url?: string;
  share_url?: string;
  view_count: number;
  like_count: number;
  comment_count: number;
  share_count: number;
  create_time: number;
}>> {
  const accessToken = await resolveToken(args, customer);

  const fields = 'id,title,video_description,duration,cover_image_url,share_url,view_count,like_count,comment_count,share_count,create_time';
  const data = await tiktokRequest('/video/list/', accessToken, 'POST', {
    max_count: Math.min(args.max_count ?? 10, 20),
    fields: fields.split(','),
  });

  return (data.videos ?? []).map((v: Record<string, unknown>) => ({
    id: String(v.id ?? ''),
    title: v.title as string | undefined,
    video_description: v.video_description as string | undefined,
    duration: Number(v.duration ?? 0),
    cover_image_url: v.cover_image_url as string | undefined,
    share_url: v.share_url as string | undefined,
    view_count: Number(v.view_count ?? 0),
    like_count: Number(v.like_count ?? 0),
    comment_count: Number(v.comment_count ?? 0),
    share_count: Number(v.share_count ?? 0),
    create_time: Number(v.create_time ?? 0),
  }));
}

export async function createVideo(
  args: { video_url: string; title?: string; description?: string; account?: string },
  customer?: Customer
): Promise<{ publish_id: string; status: string }> {
  const audit = customer ? createToolAudit(customer.id, 'tiktok:createVideo') : null;
  const auditArgs = { title: args.title };
  const accessToken = await resolveToken(args, customer);

  // Step 1: initialise upload
  const init = await tiktokRequest('/post/video/init/', accessToken, 'POST', {
    post_info: {
      title: args.title ?? '',
      description: args.description ?? '',
      disable_duet: false,
      disable_comment: false,
      disable_stitch: false,
      privacy_level: 'PUBLIC_TO_EVERYONE',
    },
    source_info: {
      source: 'PULL_FROM_URL',
      video_url: args.video_url,
    },
  });

  const publishId = init.publish_id ?? '';

  try {
    const result = { publish_id: publishId, status: 'processing' };
    if (audit) await audit.success(auditArgs);
    return result;
  } catch (err) {
    if (audit) await audit.error(auditArgs, String(err));
    throw err;
  }
}

export async function getVideoStatus(
  args: { publish_id: string; account?: string },
  customer?: Customer
): Promise<{ publish_id: string; status: string; fail_reason?: string }> {
  const accessToken = await resolveToken(args, customer);

  const data = await tiktokRequest('/post/publish/status/fetch/', accessToken, 'POST', {
    publish_id: args.publish_id,
  });

  return {
    publish_id: args.publish_id,
    status: String(data.status ?? 'unknown'),
    fail_reason: data.fail_reason as string | undefined,
  };
}
