import {
  Contact,
  Contacts,
  CreateDomainRequest,
  CreateDomainResponse,
  Domain,
  ErrorResponse,
  ListDomainsResponse,
  PricingRequest,
  PricingResponse,
  SearchRequest,
  SearchResponse,
  SearchResult,
  SetContactsRequest,
  SetNameserversRequest,
} from "./types/index.js";
import AxiosClient from "./AxiosClient.js";
import axios from "axios";
import { default as NameApiError } from "./NameApiError.js";

class NameComDomains extends AxiosClient {
  async listDomains(perPage = 0, page = 0) : Promise<ListDomainsResponse> {
    try {
      let params = "";
      if (page > 0 && perPage > 0) {
        params = `?perPage=${perPage}&page=${page}`;
      }
      console.log("Axios: "+this.axiosInstance);
      console.log("Params: "+params);
      const response = await this.axiosInstance.get(`/domains${params}`);
      return response.data as ListDomainsResponse;
    } catch (error: any) {
      throw new Error(`Error listing domains: ${error.message}`);
    }
  }

  async getDomain(domainName: string) {
    try {
      const response = await this.axiosInstance.get(`/domains/${domainName}`);
      return response.data;
    } catch (error: any) {
      throw new Error(`Error getting domain details: ${error.message}`);
    }
  }

  async createDomain(domainData: CreateDomainRequest) : Promise<CreateDomainResponse> {
    try {
      console.log(`curl -X POST -H "Content-Type: application/json" -u "${this.username+':'+this.token}" -d '${JSON.stringify(domainData)}' ${this.baseUrl}/domains`);
      const response = await this.axiosInstance.post(`/domains`, domainData);
      if (response.status >= 400 && response.status < 500) {
        const responseBody = response.data;
        throw new Error(JSON.stringify({httpStatusCode: response.status, ...responseBody}));
      }
      return response.data as CreateDomainResponse;
    } catch (error: any) {
      if (error.response) {
        const responseBody = error.response.data;
        throw new Error(JSON.stringify({catchedError: true, httpStatusCode: error.response.status, ...responseBody}));
      }
      throw new Error(`Error creating domain: ${error.message}`);
    }
  }

  async enableWhoisPrivacy(domainName: string) {
    try {
      const response = await this.axiosInstance.post(
        `/domains/${domainName}:enableWhoisPrivacy`
      );
      return response.data;
    } catch (error: any) {
      throw new Error(`Error enabling WHOIS privacy: ${error.message}`);
    }
  }

  async disableWhoisPrivacy(domainName: string) {
    try {
      const response = await this.axiosInstance.post(
        `/domains/${domainName}:disableWhoisPrivacy`
      );
      return response.data;
    } catch (error: any) {
      throw new Error(`Error disabling WHOIS privacy: ${error.message}`);
    }
  }

  async enableAutorenew(domainName: string) {
    try {
      const response = await this.axiosInstance.post(
        `/domains/${domainName}:enableAutorenew`
      );
      return response.data;
    } catch (error: any) {
      throw new Error(`Error enabling autorenew: ${error.message}`);
    }
  }

  async disableAutorenew(domainName: string) {
    try {
      const response = await this.axiosInstance.post(
        `/domains/${domainName}:disableAutorenew`
      );
      return response.data;
    } catch (error: any) {
      throw new Error(`Error disabling autorenew: ${error.message}`);
    }
  }

  async renewDomain(domainName: string, years: number) {
    try {
      const response = await this.axiosInstance.post(
        `/domains/${domainName}:renew`,
        { years }
      );
      return response.data;
    } catch (error: any) {
      throw new Error(`Error renewing domain: ${error.message}`);
    }
  }

  // Implement additional methods for get pricing, get auth code, purchase privacy,
  // set nameservers, set contacts, lock/unlock domain, check availability, search,
  // and search stream following the same pattern.

  async getPricingForDomain(domainName: string, years: number): Promise<PricingResponse>  {
    try {
      const response = await this.axiosInstance.get(
        `/domains/${domainName}:getPricing`,
        {
          params: { years },
        }
      );
      return response.data as PricingResponse;
    } catch (error: any) {
      //console.error('Failed to get pricing for domain:', error);
      throw error;
    }
  }

  async getAuthCodeForDomain(domainName: string) {
    try {
      const response = await this.axiosInstance.get(
        `/domains/${domainName}:getAuthCode`
      );
      return response.data;
    } catch (error) {
      //console.error('Failed to get auth code for domain:', error);
      throw error;
    }
  }

  async purchasePrivacy(domainName: string, privacyRequest: PricingRequest) {
    try {
      const response = await this.axiosInstance.post(
        `/domains/${domainName}:purchasePrivacy`,
        privacyRequest
      );
      return response.data; // Assuming this is the PrivacyResponse
    } catch (error) {
      // console.error('Error purchasing privacy:', error);
      throw error;
    }
  }

  async setNameservers(domainName: string, nameservers: SetNameserversRequest) {
    try {
      const response = await this.axiosInstance.post(
        `/domains/${domainName}:setNameservers`,
        nameservers
      );
      return response.data;
    } catch (error) {
      //console.error('Error setting nameservers:', error.response.data);
      throw error;
    }
  }

  async setContacts(domainName: string, contacts: SetContactsRequest) {
    try {
      const response = await this.axiosInstance.post(
        `/domains/${domainName}:setContacts`,
        contacts
      );
      return response.data;
    } catch (error) {
      // console.error('Error setting contacts:', error.response.data);
      throw error;
    }
  }

  async lockDomain(domainName: string) {
    try {
      const response = await this.axiosInstance.post(
        `/domains/${domainName}:lock`
      );
      return response.data;
    } catch (error) {
      // console.error('Error locking domain:', error.response.data);
      throw error;
    }
  }

  async unlockDomain(domainName: string) {
    try {
     // console.log(`curl -X POST -H "Content-Type: application/json" -u "${this.username+':'+this.token}" -d '${JSON.stringify(domainData)}' ${this.baseUrl}/domains`);
      const response = await this.axiosInstance.post(
        `/domains/${domainName}:unlock`
      );
        if (response.status >= 400 && response.status < 500) {
        const responseBody = response.data;
        throw new NameApiError("API Error 400", true, response.status, responseBody);
      }
      return response.data as CreateDomainResponse;
    } catch (error: any) {
      if (error.response) {
        const responseBody = error.response.data;
        throw new NameApiError("API Error", true, error.response.status, responseBody);
      }
      throw new NameApiError("API Error", true, 500, {message: error.message, details: "Generic Error"});
    }
  }

  async checkAvailability(domainName: string): Promise<SearchResult[]> {
    try {
      const response = await this.axiosInstance.get(
        `/domains/${domainName}:checkAvailability`
      );
      return response.data as SearchResult[] ;
    } catch (error) {
      //   console.error('Error checking domain availability:', error.response.data);
      throw error;
    }
  }

  async search(query: SearchRequest): Promise<SearchResponse> {
    try {
      const response = await this.axiosInstance.post(
        `/domains:search`,
        {
          ...query,
        }
      );
      return response.data as SearchResponse;
    } catch (error) {
      // console.error('Error searching for domain:', error.response.data);
      throw error;
    }
  }

  async searchStream(query: SearchRequest): Promise<any> {
    try {
      const response = await
      axios({
        method: 'post',
        url: this.baseUrl+'/domains:searchStream',
        data: {
          ...query
        },
        headers: {
          'Content-Type': 'application/json',
          'Authorization': 'Basic ' + Buffer.from(this.username+':'+this.token).toString('base64'),
        },
        responseType: 'stream' // This is important to handle the response as a stream
      });
      return response;
    } catch (error) {
      //  console.error('Error searching for domain:', error.response.data);
      throw error;
    }
  }

  /*     async deleteDomain(domainName) {
        try {
          const response = await this.axiosInstance.delete(`/domains/${domainName}`);
          return response.data;
        } catch (error) {
          console.error('Error deleting domain:', error.response.data);
          throw error;
        }
      }
   */
}

export default NameComDomains;
