import crypto from 'crypto';
import type { _1PanelPaginationResponse, _1PanelResponse, _1PanelWebsite } from '~/types/1panel';
import { isBinaryString } from '~/utils/file-utils';
import { generateUUID } from '~/utils/uuid';
import { request } from '../../lib/fetch';

export interface _1PanelBaseParams {
  serverUrl: string;
  apiKey: string;
  version?: 'v2';
}

export interface CreateWebsiteParams extends _1PanelBaseParams {
  alias: string;
  primaryDomain?: string;
  proxyProtocol?: string;
  isSSL?: boolean;
}

export interface GetWebsiteParams extends _1PanelBaseParams {
  siteId: number;
}

export interface UploadFileContent {
  path: string;
  data: string;
  fileName: string;
}

export interface UploadFileParams extends _1PanelBaseParams {
  path: string;
  data: string;
  fileName: string;
}

export interface UploadFilesParams extends _1PanelBaseParams {
  files: UploadFileContent[];
}

export interface DeleteWebsiteParams extends _1PanelBaseParams {
  siteId: number;
}

export interface ToggleAccessParams extends _1PanelBaseParams {
  siteId: number;
  operate: 'start' | 'stop';
}

function get1PanelHost(serverUrl: string, version = 'v2') {
  return `${serverUrl.replace(/\/$/, '')}/api/${version}`;
}

export async function getWebsiteList(
  serverUrl: string,
  apiKey: string,
  version = 'v2',
): Promise<_1PanelResponse<_1PanelWebsite[]>> {
  const response = await request(`${get1PanelHost(serverUrl, version)}/websites/list`, {
    method: 'GET',
    headers: {
      ...getAuthHeaders(apiKey),
      'Content-Type': 'application/json',
    },
  });

  if (!response.ok) {
    throw new Error(`Failed to fetch website list: ${response.statusText}`);
  }
  return (await response.json()) as _1PanelResponse<_1PanelWebsite[]>;
}

export async function createWebsite(params: CreateWebsiteParams) {
  const { serverUrl, apiKey, version = 'v2', alias, primaryDomain, proxyProtocol, isSSL } = params;
  const domain = primaryDomain || `${alias}.upage.ai`;
  const response = await request(`${get1PanelHost(serverUrl, version)}/websites`, {
    method: 'POST',
    headers: {
      ...getAuthHeaders(apiKey),
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      IPV6: false,
      alias,
      appType: 'installed',
      domains: [
        {
          domain,
          port: 80,
          ssl: isSSL || false,
        },
      ],
      appinstall: {
        appId: 0,
        name: '',
        appDetailId: 0,
        params: {},
        version: '',
        appkey: '',
        advanced: false,
        cpuQuota: 0,
        memoryLimit: 0,
        memoryUnit: 'MB',
        containerName: '',
        allowPort: false,
      },
      createDb: false,
      enableFtp: false,
      enableSSL: false,
      ftpPassword: '',
      ftpUser: '',
      otherDomains: '',
      primaryDomain: domain || '',
      proxy: '',
      proxyAddress: '',
      proxyProtocol: proxyProtocol || 'http://',
      proxyType: 'tcp',
      remark: '',
      runtimeType: 'php',
      port: 9000,
      siteDir: '',
      taskID: generateUUID(),
      type: 'static',
      webSiteGroupId: 1,
    }),
  });

  if (!response.ok) {
    return {
      code: response.status,
      data: {
        message: response.statusText,
      },
    };
  }

  return {
    code: response.status,
    data: {
      domain: domain,
    },
  };
}

export async function getWebsite(params: GetWebsiteParams) {
  const { serverUrl, apiKey, version = 'v2', siteId } = params;
  const response = await request(`${get1PanelHost(serverUrl, version)}/websites/${siteId}`, {
    method: 'GET',
    headers: {
      ...getAuthHeaders(apiKey),
    },
  });

  if (!response.ok) {
    throw new Error(`Failed to get website: ${response.statusText}`);
  }

  return response.json() as Promise<_1PanelResponse<_1PanelWebsite>>;
}

export async function getWebsiteByPrimaryDomain(
  serverUrl: string,
  apiKey: string,
  primaryDomain: string,
  version = 'v2',
) {
  const response = await request(`${get1PanelHost(serverUrl, version)}/websites/search`, {
    method: 'POST',
    headers: {
      ...getAuthHeaders(apiKey),
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      name: primaryDomain,
      order: 'descending',
      orderBy: 'favorite',
      page: 1,
      pageSize: 10,
      type: '',
      websiteGroupId: 0,
    }),
  });

  if (!response.ok) {
    throw new Error(`Failed to get website by primary domain: ${response.statusText}`);
  }

  return response.json() as Promise<_1PanelResponse<_1PanelPaginationResponse<_1PanelWebsite>>>;
}

export async function uploadFiles(params: UploadFilesParams) {
  const { serverUrl, apiKey, version = 'v2', files } = params;
  try {
    for (const file of files) {
      await uploadSingleContent({
        serverUrl,
        apiKey,
        version,
        path: file.path,
        data: file.data,
        fileName: file.fileName,
      });
    }
  } catch (error) {
    const errorMessage = error instanceof Error ? error.message : String(error);
    throw new Error(`Upload files failed: ${errorMessage}`);
  }
}

export async function uploadSingleContent(params: UploadFileParams) {
  const { serverUrl, apiKey, version = 'v2', path, data, fileName } = params;
  try {
    const formData = new FormData();
    const fileContent = isBinaryString(data) ? Buffer.from(data, 'binary') : data;
    const fileBlob = new Blob([fileContent], { type: 'application/octet-stream' });
    const file = new File([fileBlob], fileName, { type: 'application/octet-stream' });

    formData.append('file', file);
    formData.append('path', path);
    formData.append('overwrite', 'True');

    const response = await request(`${get1PanelHost(serverUrl, version)}/files/upload`, {
      method: 'POST',
      headers: {
        ...getAuthHeaders(apiKey),
      },
      body: formData,
    });

    if (!response.ok) {
      throw new Error(`Upload failed with status: ${response.status} ${response.statusText}`);
    }

    const result = (await response.json()) as _1PanelResponse<{ message: string }>;
    if (result.code !== 200) {
      throw new Error(`Upload failed with status: ${result.data?.message || 'Unknown error'}`);
    }
    return result.data;
  } catch (error) {
    const errorMessage = error instanceof Error ? error.message : String(error);
    throw new Error(`Upload file failed: ${path} - ${errorMessage}`);
  }
}

export async function deleteWebsite(params: DeleteWebsiteParams) {
  const { serverUrl, apiKey, version = 'v2', siteId } = params;
  const deleteResponse = await request(`${get1PanelHost(serverUrl, version)}/websites/del`, {
    method: 'POST',
    headers: {
      ...getAuthHeaders(apiKey),
    },
    body: JSON.stringify({
      deleteApp: false,
      deleteBackup: false,
      forceDelete: false,
      id: siteId,
    }),
  });

  if (!deleteResponse.ok) {
    throw new Error(`Failed to delete website: ${deleteResponse.statusText}`);
  }
  return true;
}

export async function toggleAccessWebsite(params: ToggleAccessParams) {
  const { serverUrl, apiKey, version = 'v2', siteId, operate } = params;
  const response = await request(`${get1PanelHost(serverUrl, version)}/websites/operate`, {
    method: 'POST',
    headers: {
      ...getAuthHeaders(apiKey),
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      id: siteId,
      operate,
    }),
  });

  if (!response.ok) {
    throw new Error(`Failed to toggle access: ${response.statusText}`);
  }

  const result = (await response.json()) as _1PanelResponse<{ message: string }>;
  if (result.code !== 200) {
    throw new Error(`Failed to toggle access: ${result.data?.message || 'Unknown error'}`);
  }

  return true;
}

function getAuthHeaders(apiKey: string) {
  const timestamp = Math.floor(Date.now() / 1000).toString();

  const content = `1panel${apiKey}${timestamp}`;
  const token = crypto.createHash('md5').update(content).digest('hex');

  return {
    '1Panel-Token': token,
    '1Panel-Timestamp': timestamp,
    'Accept-Language': 'zh',
  };
}
