import recordAxiosInstance from "@/shared/services/recordAxiosInstance";
import {
  TemplateResource,
  TemplateResponse,
  ResourceTypeResponse,
  CreateTemplatePayload,
  TemplateSampleRequest,
  TemplateSampleResponse,
  TemplateSampleSetting,
  TemplateSettingsByUnitResponse,
  TemplateSettingValueBulkItem,
  TemplateSettingValueHistoryResponse,
} from "../TemplateConfiguration/types/templateTypes";
import { XSSUploadValidator } from "@/shared/services/validation";
import {
  buildTemplateRequestHeaders,
  parseRecordApiError,
} from "./templateApiUtils";

const tenantHeaders = buildTemplateRequestHeaders();

const apiInstance = recordAxiosInstance;

const normalizeTemplateItem = (
  item: Record<string, unknown>,
): TemplateResource => {
  return {
    ...item,
    name: (item.name as Record<string, string>) || { am: "", en: "" },
    description: (item.description as Record<string, string>) || {
      am: "",
      en: "",
    },
  } as TemplateResource;
};

export const TemplateService = {
  async getResourceTypes(): Promise<ResourceTypeResponse> {
    const response = await apiInstance.get("/resource_types", {
      headers: tenantHeaders,
    });
    return response.data;
  },

  async getAllTemplates(
    params?: Record<string, unknown>,
  ): Promise<TemplateResponse> {
    try {
      const response = await apiInstance.get("/templates", {
        params,
        headers: tenantHeaders,
      });
      let items = (response.data.items || response.data || []).map(
        normalizeTemplateItem,
      );

      // Client-side filtering by search
      if (params?.search && typeof params.search === "string") {
        const searchLower = params.search.toLowerCase();
        items = items.filter(
          (item: TemplateResource) =>
            item.name?.en?.toLowerCase().includes(searchLower) ||
            item.name?.am?.toLowerCase().includes(searchLower) ||
            item.description?.en?.toLowerCase().includes(searchLower) ||
            item.description?.am?.toLowerCase().includes(searchLower),
        );
      }

      return {
        count: items.length,
        items,
      };
    } catch (error) {
      console.error("Error fetching templates:", error);
      return {
        count: 0,
        items: [],
      };
    }
  },

  async getTemplates(
    params?: Record<string, unknown>,
  ): Promise<TemplateResponse> {
    const { resourceTypeId, search, ...otherParams } = params || {};

    // resourceTypeId is required for the API endpoint
    if (!resourceTypeId) {
      return {
        count: 0,
        items: [],
      };
    }

    const response = await apiInstance.get(
      `/resources/list-with-presigned/${resourceTypeId}`,
      { params: otherParams, headers: tenantHeaders },
    );

    let items = (response.data.items || []).map(normalizeTemplateItem);

    // Client-side filtering by search
    if (search && typeof search === "string") {
      const searchLower = search.toLowerCase();
      items = items.filter(
        (item: TemplateResource) =>
          item.name?.en?.toLowerCase().includes(searchLower) ||
          item.name?.am?.toLowerCase().includes(searchLower) ||
          item.description?.en?.toLowerCase().includes(searchLower) ||
          item.description?.am?.toLowerCase().includes(searchLower),
      );
    }

    return {
      count: items.length,
      items,
    };
  },

  async getTemplate(id: string): Promise<TemplateResource> {
    const response = await apiInstance.get(
      `/resources/with-presigned?id=${id}`,
      { headers: tenantHeaders },
    );
    return normalizeTemplateItem(response.data);
  },

  async getTemplateWithPresigned(
    resourceTypeId: string,
    templateId: string,
  ): Promise<TemplateResource> {
    try {
      const response = await apiInstance.get(
        `/resources/list-with-presigned/${resourceTypeId}`,
        { headers: tenantHeaders },
      );
      const items = (response.data.items || []).map(normalizeTemplateItem);
      const template = items.find(
        (item: TemplateResource) => item.id === templateId,
      );
      if (!template) {
        throw new Error("Template not found");
      }
      return template;
    } catch (error: unknown) {
      const axiosError = error as Record<string, unknown>;
      // If the file hasn't been uploaded successfully, try to get basic template info
      if ((axiosError.response as Record<string, unknown>)?.status === 400) {
        try {
          const response = await apiInstance.get(
            `/resources/with-presigned?id=${templateId}`,
            { headers: tenantHeaders },
          );
          return normalizeTemplateItem(response.data);
        } catch {
          throw error;
        }
      }
      throw error;
    }
  },

  async createTemplate(data: CreateTemplatePayload): Promise<TemplateResource> {
    const response = await apiInstance.post("/resources", data, {
      headers: tenantHeaders,
    });
    return normalizeTemplateItem(response.data);
  },

  async updateTemplate(
    id: string,
    data: Partial<CreateTemplatePayload>,
  ): Promise<TemplateResource> {
    const response = await apiInstance.put(`/resources/${id}`, data, {
      headers: tenantHeaders,
    });
    return normalizeTemplateItem(response.data);
  },

  async deleteTemplate(id: string): Promise<void> {
    await apiInstance.delete(`/resources/${id}`, { headers: tenantHeaders });
  },

  async uploadFile(file: File, uploadUrl?: string) {
    if (!uploadUrl) {
      console.warn("No upload URL provided, skipping file upload");
      return null;
    }

    const validationResult = await XSSUploadValidator.validateFileForUpload(
      file,
      {
        allowedMimeTypes: [
          "image/png",
          "image/jpeg",
          "image/gif",
          "image/webp",
          "application/pdf",
        ],
        allowedExtensions: [".png", ".jpg", ".jpeg", ".gif", ".webp", ".pdf"],
        maxSizeMB: 50,
        uploadContext: "signature",
      },
    );

    if (!validationResult.isValid) {
      throw new Error(
        validationResult.clientValidation.fileName?.error ||
          validationResult.clientValidation.extension?.error ||
          validationResult.clientValidation.mimeType?.error ||
          validationResult.clientValidation.size?.error ||
          "File validation failed",
      );
    }

    const response = await fetch(uploadUrl, {
      method: "PUT",
      headers: {
        "Content-Type": file.type,
      },
      body: file,
    });

    if (!response.ok) {
      const text = await response.text();
      throw new Error(
        `Upload failed: ${response.status} ${response.statusText}\n${text}`,
      );
    }

    return response;
  },

  async updateUploadStatus(
    id: string,
    uploadedSuccessfully: boolean,
  ): Promise<void> {
    await apiInstance.put(
      `/resources/change-status/${id}`,
      { isCurrent: uploadedSuccessfully },
      { headers: tenantHeaders },
    );
  },

  async generateSampleTemplate(
    templateId: string,
    payload: TemplateSampleRequest,
    unitId?: string,
  ): Promise<TemplateSampleResponse> {
    try {
      const response = await apiInstance.post(
        `/templates/${templateId}/sample`,
        payload,
        {
          responseType: "arraybuffer",
          headers: buildTemplateRequestHeaders(unitId),
        },
      );

      // Convert ArrayBuffer to base64 data URL
      const blob = new Blob([response.data], { type: "application/pdf" });
      const url = URL.createObjectURL(blob);

      return {
        pdf: url,
        contentType: "application/pdf",
      };
    } catch (error) {
      console.error("Error generating sample template:", error);
      throw new Error(
        parseRecordApiError(error, { arrayBufferResponse: true }),
      );
    }
  },

  async getTemplateSettingsByUnit(
    templateId: string,
    unitId?: string,
  ): Promise<TemplateSettingsByUnitResponse> {
    try {
      const response = await apiInstance.get(
        `/template-settings/by-unit/${templateId}`,
        { headers: buildTemplateRequestHeaders(unitId) },
      );
      const responseData = response.data || {};
      return {
        count: responseData.count || 0,
        items: responseData.items || [],
        groups: responseData.groups || [],
      };
    } catch (error) {
      console.error("Error fetching template settings by unit:", error);
      return { count: 0, items: [], groups: [] };
    }
  },

  async saveTemplateSettingValues(
    values: Array<{
      templateSettingId: string;
      resourceId: string | null;
      value: Record<string, string>;
    }>,
  ): Promise<void> {
    try {
      await Promise.all(
        values.map((value) =>
          apiInstance.post(`/template-setting-values`, value, {
            headers: tenantHeaders,
          }),
        ),
      );
    } catch (error) {
      console.error("Error saving template setting values:", error);
      throw error;
    }
  },
  async saveBulkTemplateSettingValues(
    values: TemplateSettingValueBulkItem[],
    unitId?: string,
  ): Promise<void> {
    try {
      await apiInstance.post(`/template-setting-values/bulk`, values, {
        headers: buildTemplateRequestHeaders(unitId),
      });
    } catch (error) {
      console.error("Error saving template setting values:", error);
      throw new Error(parseRecordApiError(error));
    }
  },

  async revertUnitOverride(
    templateSettingId: string,
    unitId?: string,
  ): Promise<void> {
    try {
      await apiInstance.delete(
        `/template-setting-values/unit-override/${templateSettingId}`,
        { headers: buildTemplateRequestHeaders(unitId) },
      );
    } catch (error) {
      console.error("Error reverting template setting override:", error);
      throw new Error(parseRecordApiError(error));
    }
  },

  async getTemplateSettingValueHistory(
    templateSettingId: string,
    unitId?: string,
  ): Promise<TemplateSettingValueHistoryResponse> {
    try {
      const response = await apiInstance.get(
        `/template-setting-values/${templateSettingId}/history`,
        { headers: buildTemplateRequestHeaders(unitId) },
      );
      const data = response.data ?? {};
      return {
        count: data.count ?? (Array.isArray(data.items) ? data.items.length : 0),
        items: Array.isArray(data.items) ? data.items : [],
      };
    } catch (error) {
      console.error("Error fetching template setting history:", error);
      throw new Error(parseRecordApiError(error));
    }
  },

  async restoreTemplateSettingFromHistory(
    templateSettingId: string,
    historyId: string,
    unitId?: string,
  ): Promise<void> {
    try {
      await apiInstance.post(
        `/template-setting-values/${templateSettingId}/restore/${historyId}`,
        {},
        { headers: buildTemplateRequestHeaders(unitId) },
      );
    } catch (error) {
      console.error("Error restoring template setting from history:", error);
      throw new Error(parseRecordApiError(error));
    }
  },
};
